题目链接:Problem - 1548B - Codeforces Integers Have Friends
题意求一个序列最长子序列,这个最长子序列所有的数对一个确定的数取模后的值相等。这需要用到一个数论的知识,转化为求他们的绝对值差分数组的最长子序列的gcd大于1。转化到这一步就有两个思路,一种是采用线段树来维护区间gcd,一种则是使用st表来维护。习惯哪个用哪个,个人比较喜欢线段树,之后使用尺取来更新最长的子序列。
#include<bits/stdc++.h>
#define int long long
#define ls rt<<1
#define rs rt<<1|1
const int N=2e5+5;
using namespace std;
int T,n,a[N];
struct node{
int gcd;
}t[N<<2];
int merge(int a,int b){
return b>0?merge(b,a%b):a;
}
void pushup(int rt){
t[rt].gcd=merge(t[ls].gcd,t[rs].gcd);
}
void build(int rt,int l,int r){
if(l==r){
scanf("%lld",&a[l]);
t[rt].gcd=abs(a[l]-a[l-1]);
return;
}
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(rt);
}
int query(int rt,int l,int r,int L,int R){
if(L<=l&&r<=R){
return t[rt].gcd;
}
int mid=l+r>>1;
int ans1=0,ans2=0;
if(L<=mid) ans1=query(ls,l,mid,L,R);
if(R>mid) ans2=query(rs,mid+1,r,L,R);
if(ans1==0){
return ans2;
}
else if(ans2==0){
return ans1;
}
else return merge(ans1,ans2);
}
signed main(){
scanf("%lld",&T);
while(T--){
scanf("%lld",&n);
scanf("%lld",&a[0]);
if(n==1){
printf("1\n");
continue;
}
build(1,1,n-1);
int l=1,ans=0;
for(int r=1;r<n;r++)
{
while(l<=r&&query(1,1,n-1,l,r)==1)
l++;
ans=max(ans,1LL*(r-l+2));
}
printf("%lld\n",ans);
}
return 0;
}
下面再贴一份zrz大佬的st表代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 4e5+5;
ll a[maxn];
ll b[maxn];
ll f[maxn][32];
int n;
ll gcd(ll a,ll b){
if(b==0)return a;
return gcd(b,a%b);
}
// void inits(){
// for(int i )
// }
void RMQ(){
int t = log2(n-1)+1;
for(int i = 1;i <= n-1;i++){
f[i][0] = b[i];
}
for(int i = 1;i < t;i++){
for(int j = 1;j <= n - (1<<i) ; j++){
f[j][i] = gcd(f[j][i-1],f[j+(1<<(i-1))][i-1]);
}
}
}
ll ask(int l,int r){
int t = log2(r-l+1);
if(f[l][t]>f[r-(1<<t)+1][t])return gcd(f[l][t],f[r-(1<<t)+1][t]);
else return gcd(f[r-(1<<t)+1][t],f[l][t]);
}
int main(){
int t;
scanf("%d",&t);
// inits();
while(t--){
scanf("%d",&n);
for(int i = 1;i<=n;i++){
scanf("%lld",&a[i]);
}
if(n==1){
printf("1\n");
continue;
}
else if(n==2){
if(abs(a[2]-a[1]) != 1){
printf("2\n");
}
else printf("1\n");
continue;
}
for(int i = 2;i <= n;i++){
b[i-1] = abs(a[i] - a[i-1]);
}
RMQ();
int l,r;
l = r = 1;
int ans = 1;
while(r<n){
if(l>=r){
if(b[l]!=1)ans = max(2,ans);
r++;continue;
}
ll g = ask(l,r);
if(g>1){
r++;
ans = max(ans,r-l+1);
}
else l++;
}
printf("%d\n",ans);
}
}