版权声明:转载者乖乖♂站好 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;
}