A,B,C就不说了,又被D题卡住了.....
感觉怎么说呢,就是题解中的三个提示都已经想到了,就是不知道该怎么解决....
简述题意:题目要求你找一个区间[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表版本的:
//不等,不问,不犹豫,不回头. #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); } //以吾之血,铸吾最后的亡魂.