A,B,C就不说了,又被D题卡住了.....

感觉怎么说呢,就是题解中的三个提示都已经想到了,就是不知道该怎么解决....

D. Integers Have Friends

简述题意:题目要求你找一个区间[l,r]使得a_l%m=a_(l+1)%m=...=a_r%m。且m>=2,要求能找到的最大区间是多少。

看到取模我的想法就是将其最原本的式子写出来,a_l=c1*m+k,a_(l+1)=c2*m+k,...,a_r=cn*m+k,考虑他们之间的关系,发现有个相同的余数k,我们做个差分数组,这样他们的k就都抵消了..于是我们惊奇的发现m是他们差分数组的gcd,这样后我们就知道一个区间合法当且仅当这个区间的差分数组的gcd>=2,这样的话我们直接在原数组上做差分。长度变为n-1,题目转化成,我们需要找到一个区间,使得他们的gcd>=2,且长度最大。.....

昨天到这就gg了....找区间的话,无外乎就是固定左端点最最远的右端点,尺取法等操作,考虑尺取法的话确实发现右端点是单调递增的,但左端点移动时我们无法去除左端点的影响,这个方法暂时告歇...接着考虑我们学过的一些数据结构,gcd符合区间加法的原则(广义上的区间加法,即知道了左区间的gcd,右区间的gcd,我们就可以计算出整个区间的gcd了)。这样的话我们就可以用各种结构进行优化试试,首先我们右端点是朴素的从左向右扫的,倍增能不能呢?好像可以,只需要预处理一下就可以了。线段树作为区间之王,行不行?貌似也可以,比如说给定一个l,我们先进入l这个叶子节点,等回溯时,一点点尝试将区间往上叠加,先将右区间全部叠加上看行不行,不行的话再向下搜寻就大概可以了(我码一下试试.).

这是倍增+st表版本的:

Codeforces Round #736 (Div. 2)题解_gitCodeforces Round #736 (Div. 2)题解_git_02
//不等,不问,不犹豫,不回头.
#include<bits/stdc++.h>
#define _ 0
#define ls p<<1
#define db double
#define rs p<<1|1
#define RE register
#define P 1000000007
#define ll long long
#define INF 1000000000
#define get(x) x=read()
#define PLI pair<ll,int>
#define PII pair<int,int>
#define ull unsigned long long
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define rep(x,y,z) for(RE int x=y;x<=z;++x)
#define fep(x,y,z) for(RE int x=y;x>=z;--x)
#define go(x) for(RE int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
using namespace std;
const int N=2e5+10;
int n; 
ll a[N],b[N],f[N][22];//f[i][j]表示从第i个数开始,一共2^j个数的gcd的值. 

inline ll read()
{
    ll x=0,ff=1;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*ff;
}

inline ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}

int main()
{
//    freopen("1.in","r",stdin);
    int get(T);
    while(T--)
    {
        get(n);
        rep(i,1,n) get(a[i]);
        rep(i,1,n-1) b[i]=abs(a[i+1]-a[i]); //注意这里用绝对值,防止出现负数. 
        rep(i,1,n-1) f[i][0]=b[i];
        rep(j,1,20) 
            rep(i,1,n-1) 
            {
                if(i+(1<<j)-1>n-1) break;
                f[i][j]=gcd(f[i][j-1],f[i+(1<<(j-1))][j-1]);
            }
        ll ans=1;
        rep(i,1,n-1)//从i为起点开始向后找. 
        {
            ll gcc=f[i][0],now=i+1;
            if(gcc<2) continue; 
            fep(j,20,0) 
            {
                if(now+(1<<j)-1>n-1) continue;
                if(gcd(gcc,f[now][j])>=2)
                {
                    gcc=gcd(gcc,f[now][j]);
                    now=now+(1<<j);
                } 
            }
            ans=max(ans,now-i+1);
        }
        put(ans);
    }
    return (0^_^0);
}
//以吾之血,铸吾最后的亡魂.
View Code