zoukankan      html  css  js  c++  java
  • 联考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");
    }
    

  • 相关阅读:
    【视频+图文】带你快速掌握Java中含continue语句的双重for循环
    【小白视频学Java for循环】3分钟学会Java的for循环,让看懂for循环嵌套再不是难事
    【机器学习基础】交叉熵(cross entropy)损失函数是凸函数吗?
    【tf.keras】tensorflow datasets,tfds
    【python3基础】命令行参数及 argparse
    【机器学习实战】验证集效果比测试集好怎么办?
    [主动学习--查询策略] 01 Core-set
    Monte-Carlo Dropout,蒙特卡罗 dropout
    NumPy 会自动检测并利用 GPU 吗?
    Linux 和 Windows 查看 CUDA 和 cuDNN 版本
  • 原文地址:https://www.cnblogs.com/IzayoiDoyo/p/13355591.html
Copyright © 2011-2022 走看看