2018SD省队集训R2 D2

T1

这里写图片描述

题解

我们并不需要知道相对应位置的数字是不是相等,只要置换之后的hash值相等就行了。
hash 函数本身相当于每个位置乘上 x 的若干次方,置换之后只要改变次方的顺序就好了。

具体来说,设我们的base值是m,一段区间的hash值是 i = 0 n S i m i ,然后一个置换的hash值是 i = 0 n S i m p ( i )

如果我们设 g [ n i ] = m p ( i ) ,那么我们要求的置换的hash值是 i = 0 n S i g [ n i ] ,这是一个非常明显的卷积

那么同理一段区间的hash值也可以通过倒置的方法用卷积求出来,最后只要判断两者是不是相等就行了

代码

#include <cstdio>
#include <iostream>
#include <algorithm>
#define LL long long 
using namespace std;
const int N=1500005;
const int mod=998244353;
const int base=131;
int n,m,c,fn,r[N];LL mi[N],hash1[N],hash2[N],s[N],p[N];
LL ksm(LL a,LL k)
{
    LL ans=1;
    for (;k;k>>=1,a=a*a%mod)
      if (k&1) ans=ans*a%mod;
    return ans;
}
void NTT(LL *a,int id)
{
    for (int i=0;i<n;i++)
      if (i<r[i]) swap(a[i],a[r[i]]);
    for (int k=1;k<n;k<<=1)
    {
        LL wn=ksm(3,(mod-1)/(k<<1));
        for (int i=0;i<n;i+=(k<<1))
        {
            LL w=1;
            for (int j=0;j<k;j++,w=w*wn%mod)
            {
                LL x=a[i+j],y=w*a[i+j+k]%mod;
                a[i+j]=(x+y)%mod; a[i+j+k]=(x-y+mod)%mod;
            }
        }
    }
    if (id==-1) reverse(a+1,a+n);
}
int main()
{
    freopen("sub.in","r",stdin);
    freopen("sub.out","w",stdout);
    scanf("%d%d%d",&n,&m,&c);
    for (int i=0;i<n;i++) scanf("%lld",&p[i]),p[i]--;
    for (int i=0;i<m;i++) scanf("%lld",&s[i]);
    mi[0]=1;
    for (int i=1;i<n;i++) mi[i]=mi[i-1]*base%mod;
    for (int i=0;i<n;i++) hash1[i]=mi[n-i-1];
    for (int i=0;i<n;i++) hash2[n-i-1]=mi[p[i]];
    int fn=n;int L=0;
    for (n=1;n<=m*2;n<<=1) L++;
    for (int i=0;i<n;i++) r[i]=(r[i>>1]>>1) | ((i&1)<<L-1);
    NTT(s,1); NTT(hash1,1); NTT(hash2,1);
    for (int i=0;i<n;i++) hash1[i]=hash1[i]*s[i]%mod,hash2[i]=hash2[i]*s[i]%mod;
    NTT(hash1,-1); NTT(hash2,-1);
    for (int i=0;i<=m-fn;i++) 
      if (hash1[i+fn-1]==hash2[i+fn-1]) printf("1");else printf("0");
}

猜你喜欢

转载自blog.csdn.net/blue_cuso4/article/details/80890426
d2
今日推荐