Description
某日,小Q得到了一种新的生成 01 串的代码。
给定一个整数 Z,执行 n 次下列语句会得到一个 01 串
z=[(a*z+c)/k]%m;
if (z现在小Q已经得到了某串01串,小Q想知道有多少个可能的不同的最初的 Z 可以生成这个01串。
Input
第一行五个整数 a, c, k, m, n。
第二行 n 个连续的 01 数字描述 01 串。
Output
一行一个整数表示答案。
Sample Input
3 6 2 9 2 10
Sample Output
4
Hint
【数据规模与约定】
对于 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,0<=z< m
好题,倍增+哈希。
维护g[i][j]表示第i个数经过2^j操作过后变成的数,
维护f[i][j]表示i经过2^j变换过后的哈希值,方程手推一下就出来了。
值得注意的是JZOJ这道题卡常,双哈希被卡,大数组放前面被卡,被卡成了暴力分= =
#include<bits/stdc++.h>
using namespace std;
const int e1=31,p1=1e9+7;
const int Maxn=100005,Maxm=1000005;
char s[Maxn];
int a,c,k,m,n,len,goal1;
int f[17][Maxm];
int h1[17][Maxm];
int f1[Maxn]={1};
inline void ST(){
for(int i=1;i<=1e5;++i)f1[i]=1ll*f1[i-1]*e1%p1;
for(int i=0;i<m;++i){
f[0][i]=((1ll*a*i+c)/k)%m;
h1[0][i]=(f[0][i]>=m/2);
}
int maxlog=log2(n);
for(int j=1;j<=maxlog;++j)
for(int i=0;i<m;++i){
f[j][i]=f[j-1][f[j-1][i]];
h1[j][i]=(1ll*h1[j-1][i]*f1[(1<<j-1)]+h1[j-1][f[j-1][i]])%p1;
}
}
inline bool check(int st,int x){
int st1=0,st2=0,maxlog=log2(x);
for(int i=maxlog;i>=0;--i)if(x-(1<<i)>=0){
x-=(1<<i);
st1=(1ll*st1*f1[1<<i]+h1[i][st])%p1;
st=f[i][st];
}
return st1==goal1;
}
int main(){
// freopen("zero.in","r",stdin);
// freopen("zero.out","w",stdout);
cin>>a>>c>>k>>m>>n;
scanf("%s",s+1);
len=strlen(s+1);
for(int i=1;i<=len;++i){
goal1=(1ll*goal1*e1+(s[i]-'0'))%p1;
}
ST();
int ret=0;
for(int i=0;i<m;++i)ret+=check(i,n);
printf("%d\n",ret);
return 0;
}
/*
3 6 2 9 2
10
*/