Codeforces Round #736 (Div. 2) D

Integers Have Friends 思维、双指针、st表

大意:给定一个长度为 n 的序列,若存在一段连续的子序列 [l,r] 满足

a l m o d    m = a l + 1 m o d    m = . . . . . . = a r m o d    m a_l \mod m = a_{l+1} \mod m = ...... =a_r \mod m almodm=al+1modm=......=armodm (m>=2)则称该子序列为 友好子序列。

求满足条件的最长友好子序列长度。

思路:对于 a%m=b%m 通过移项,其实也就是 (a-b)%m=0。原问题中的友好子序列就转化成了

子序列中的任意两个数的差值都是 m 的倍数。对于三个数 a, b, c 若 (a-b)%m=0,(b-c)%m=0

那么必有 (a-c)%m=0(上面两式相加就行了)。所以只需要相邻两个数的差值是 m 的倍数就行了。m>=2 ,进一步将问题转化,[l,r] 是友好子序列,其实也就是令 b i = a i − a i − 1 b_i=a_i-a_{i-1} bi=aiai1,b 序列中的 [ l + 1 , r ] [l+1,r] [l+1,r] gcd>1。根据gcd的性质,若区间 [l,r]的gcd=1,那么[l,x] (x>r) 的gcd 也始终是1,所以可以用双指针来写。需要用st 表快速查询区间 gcd 。

代码如下:

#include <bits/stdc++.h>
#define int long long 
#define rep(i,bbb,eee) for(int i=bbb;i<=eee;i++)
#define frep(i,bbb,eee) for(int i=bbb;i>=eee;i--)
#define mem(a,b) memset(a,b,sizeof(a))
#define cout(xxx) cout<<fixed<<setprecision(xxx)
#define inf 0x3f3f3f3f
#define pb push_back
#define AC signed
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
const int N=200010,M=998244353;
int qmi(int a,int b)
{
	int res=1;
	while(b)
	{
		if(b&1)res=res*a%M;
		a=a*a%M;
		b>>=1;
	}
	return res%M;
}
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)&&ch!='-')ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}
inline void print(int x)
{   
   if(x<0){putchar('-');x=-x;}
   if(x>9) print(x/10);
   putchar(x%10+'0');
}
//____________________________________________//
int n,m,f[N][20],a[N],st[N];
void init()
{
	for(int j=0;(1<<j)<=n;j++)
	{
		for(int i=1;i+(1<<j)-1<=n;i++)
		{
			if(!j)f[i][j]=abs(a[i]-a[i-1]);
			else f[i][j]=__gcd(f[i][j-1],f[i+(1<<j-1)][j-1]);
		}
	}
}
int query(int l,int r)
{
	int k=r-l+1;
	k=st[k];
	return __gcd(f[l][k],f[r-(1<<k)+1][k]);
}
void solve()
{
	cin>>n;
	rep(i,1,n)cin>>a[i];
	init();
	int ans=1;
	for(int i=2,j=2;i<=n;i++)
	{
		while(j<i&&query(j,i)==1)j++;
		if(query(j,i)>1)ans=max(ans,i-j+2);
	}
	cout<<ans<<"\n";
}
AC main()
{
	ios::sync_with_stdio(false);cin.tie(0);
	for(int j=0;j<=18;j++)
	{
		int t=1<<j;
		if(t>=N)break;
		st[t]=j;
	}
	for(int i=1;i<N;i++)if(!st[i])st[i]=st[i-1];
	int _=1;
	cin>>_;
	while(_--)solve();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值