【JZOJ A组】01 串

版权声明:转载者乖乖♂站好 https://blog.csdn.net/Eric1561759334/article/details/82588738

Description

某日,小 Q 得到了一种新的生成 01 串的代码
给定一个整数 Z,执行 n 次下列语句会得到一个 01 串
z=[(a*z+c)/k]%m;
if (z

Input

第一行五个整数 a, c, k, m, n。
第二行 n 个连续的 01 数字描述 01 串。

Output

一行一个整数表示答案

Sample Input

3 6 2 9 2
10

Sample Output

4

Data Constraint

对于 30%的数据,1<=n,m<=10^3
对于 60%的数据,1<=n<=10^3
对于 100%的数据,1<=n<=10^5,1<=m<=10^6,0<=a,c<=m,1<=k<=m

思路

考虑每个数,他生成的是一个唯一确定的数,则我们考虑求出 f[i][j]表示 i 进过 2^j次变化后生成串的哈希值,这个可以 nlogn 求,然后枚举 0 到 m-1 的每个数,logn 求其哈希值与原串比较即可。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const ll mo=10890604,w=31,N=1e5+77,M=177,inf=0x3f3f3f3f;
char st[N];
int a,c,k,m,mm,n,p[N],ans,_2[23],g[17][N*10];
ll f[17][N*10],s,t,z[N];

bool check(int x)
{
    t=0;
    for(int i=16;i+1;i--)
        if(n&_2[i])t=(t*z[_2[i]]%mo+f[i][x])%mo,x=g[i][x];
    return t==s;
}

int main()
{
    freopen("zero.in","r",stdin);
    freopen("zero.out","w",stdout);
    _2[0]=z[0]=1;
    for(int i=1;i<20;i++)_2[i]=_2[i-1]<<1;
    scanf("%d%d%d%d%d",&a,&c,&k,&m,&n);
    scanf("%s",st+1);
    for(int i=1; i<=n; i++) p[i]=st[i]-48,z[i]=z[i-1]*w%mo,s=s*w%mo+p[i];
    mm=m>>1;
    for(int i=0;i<m;i++)g[0][i]=(((ll)i*a+c)/k)%m,f[0][i]=(g[0][i]>=mm);

    for(int j=1;j<17;j++)
        for(int i=0;i<m;i++)
            g[j][i]=g[j-1][g[j-1][i]],
            f[j][i]=(f[j-1][g[j-1][i]]+f[j-1][i]*z[_2[j-1]]%mo)%mo;

    for(int i=0;i<m;i++)
        if(check(i))ans++;

    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Eric1561759334/article/details/82588738
今日推荐