联考20200719 T2 寻找规律



分析:
首先\(K+1\)个位置的值才能确定一个次数为\(K\)的函数
所以如果\(K\geq n\)直接输出0就好了,相当于我们要处理的\(K\)范围只有\(10^5\)

题解里面这个“两个序列相似的充要条件就是他们的特征序列相等”看不大懂
听了机房神仙的做法,NTT差分+KMP就能做
首先一个\(K\)次函数能算出来的连续\(n\)个值,差分\(K+1\)次得到的长度为\(n-K-1\)的序列必定全为0
可以理解为\(K+1\)次导数吧(?),不懂,数学只有小学水平
两个序列相减之后的差分序列全0,可以变换成两个序列先差分再相减序列全为0
相当于两个序列差分之后要相同
\(B\)要移位,老套路将\(B\)复制一份接到自己后面,差分之后KMP比较即可
\(K+1\)次暴力差分复杂度为\(O(n^2)\),考虑优化
列一下差分式子:

\[b_i=\sum_{j=0}^{K+1}(-1)^{K+1-j}\binom{K+1}{j}a_{i+j} \]

这个是卷积形式,移下位用NTT算就行了
复杂度\(O(nlogn)\)

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<string>

#define maxn 1000005
#define INF 0x3f3f3f3f
#define MOD 998244353

using namespace std;

inline int getint()
{
	int num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

int n,K;
int a[maxn],b[maxn];
int rev[maxn];
int fac[maxn],inv[maxn];
int fail[maxn];

inline int C(int p,int q)
{return 1ll*fac[p]*inv[q]%MOD*inv[p-q]%MOD;}

inline int ksm(int num,int k)
{
	int ret=1;
	for(;k;k>>=1,num=1ll*num*num%MOD)if(k&1)ret=1ll*ret*num%MOD;
	return ret;
}

inline void NTT(int *a,int N,int opt)
{
	for(int i=0;i<N;i++)if(rev[i]<i)swap(a[i],a[rev[i]]);
	for(int i=1;i<N;i<<=1)
	{
		int wn=ksm(3,(MOD-1)/(i<<1));
		if(!~opt)wn=ksm(wn,MOD-2);
		for(int j=0;j<N;j+=i<<1)for(int k=0,w=1;k<i;k++,w=1ll*w*wn%MOD)
		{
			int x=a[j+k],y=1ll*w*a[i+j+k]%MOD;
			a[j+k]=(x+y)%MOD,a[i+j+k]=(x-y+MOD)%MOD;
		}
	}
	if(!~opt)for(int i=0,Inv=ksm(N,MOD-2);i<N;i++)a[i]=1ll*a[i]*Inv%MOD;
}

inline void solve(int *A,int N)
{
	static int B[maxn];
	int len=1;
	while(len<=N+K)len<<=1;
	for(int i=0;i<len;i++)rev[i]=(rev[i>>1]>>1)|(i&1?len>>1:0);
	for(int i=0;i<=K;i++)B[i]=i&1?MOD-C(K,i):C(K,i);
	for(int i=K+1;i<len;i++)B[i]=0;
	NTT(A,len,1),NTT(B,len,1);
	for(int i=0;i<len;i++)A[i]=1ll*A[i]*B[i]%MOD;
	NTT(A,len,-1);
	for(int i=0;i<N-K;i++)A[i]=A[i+K];
	for(int i=N-K;i<len;i++)A[i]=0;
}

inline void getfail()
{
	fail[0]=-1;
	for(int i=1;i<n-K;i++)
	{
		int j=fail[i-1];
		while(~j&&a[j+1]!=a[i])j=fail[j];
		if(a[j+1]==a[i])fail[i]=j+1;
		else fail[i]=-1;
	}
}

int main()
{
	n=getint(),K=getint();
	for(int i=0;i<n;i++)a[i]=getint();
	for(int i=0;i<n;i++)b[i]=b[i+n]=getint();
	if((K++)>=n){printf("0\n");return 0;}
	fac[0]=fac[1]=inv[0]=inv[1]=1;
	for(int i=2;i<=K;i++)fac[i]=1ll*i*fac[i-1]%MOD;
	for(int i=2;i<=K;i++)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
	for(int i=2;i<=K;i++)inv[i]=1ll*inv[i]*inv[i-1]%MOD;
	solve(a,n);
	solve(b,2*n);
	getfail();
	int tmp=-1;
	for(int i=0;i<2*n-K;i++)
	{
		while(~tmp&&a[tmp+1]!=b[i])tmp=fail[tmp];
		if(a[tmp+1]==b[i])tmp++;
		if(tmp==n-K-1){printf("%d\n",i-n+K+1);return 0;}
	}
	printf("-1\n");
}

posted @ 2020-07-21 15:59  Izayoi_Doyo  阅读(335)  评论(0编辑  收藏  举报