题意
给你三个参数 n , a , p n,a,p n,a,p,你能用这个三个参数生成一个长度为 n n n的 01 01 01串 c c c,再给你一个长度为 m m m的 01 01 01串 b b b,问 b b b在 c c c中出现多少次,可以重叠;
题解
如果我们能按照他给的方法生成串 c c c,那么可以跑个kmp什么的得到答案,但是有一个问题, n n n非常大,我们没有办法把串 c c c生成出来;
那么我们换一种方式,设 F i = ( a ∗ i + b ) % n F_i=(a*i+b)\%n Fi=(a∗i+b)%n, b i = F i < P ? 0 : 1 , b_i=F_i<P?0:1, bi=Fi<P?0:1,因为有 G C D ( a , n ) = 1 GCD(a,n)=1 GCD(a,n)=1,那么 n n n个 F i F_i Fi的值互不相同,用裴蜀定理可以证明;再观察这个 F F F,它其实是一个等差数列,公差为 a a a,如果我们确定了第一项在 c c c中的位置,后面的就都确定了;那么我们现在有了一种新的思路,找出那些位置作为第一项是合法的;考虑这么两个不等式,如果 b b b串中第 p p p个位置是 0 0 0的话有 0 ≤ F 1 + a ∗ ( p − 1 ) < P 0\leq F_1+a*(p-1)<P 0≤F1+a∗(p−1)<P,是 1 1 1的话有 P ≤ F i + a ∗ ( p − 1 ) ≤ n − 1 P\leq F_i+a*(p-1) \leq n-1 P≤Fi+a∗(p−1)≤n−1,通过移项,我们就能得到对 F 1 F_1 F1进行限制的范围,但是只知道那些位置可以的话,我们并不好计算可行的第一项位置,不过我们可以反过来计算不可行的区间,然后用扫描线求出区间并,总长度减去这些不可行的位置,就能得到最终的答案了,不要忘记后面 m − 1 m-1 m−1个位置是绝对不可行的;
#include<bits/stdc++.h>
#define Fst first
#define Snd second
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long LL;
typedef unsigned int UI;
typedef unsigned long long ULL;
template<typename T> inline void read(T& x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template<typename T, typename... U> inline void read(T& x, U& ... y) {
read(x), read(y...);
}
const int N=2e6+10;
int n,a,b,m,P,cnt;
char S[N];
struct Data {
int p,w;
Data () {}
Data (int a,int b) :p(a),w(b) {}
bool operator <(const Data& rhs) const {
return p<rhs.p;
}
}A[N<<2];
void ADD(int l,int r) {
A[++cnt]=Data(l,1); A[++cnt]=Data(r+1,-1);
}
int main() {
read(n,a,b,P,m); scanf("%s",S+1);
for(int i=1,t=0;i<=m;++i,(t+=a)%=n) {
if(S[i]=='0') {
if(t<=P) ADD(P-t,n-1-t);
else ADD(n-t+P,n-1),ADD(0,n-1-t);
}
else {
if(t<P) ADD(0,P-1-t),ADD(n-t,n-1);
else ADD(n-t,n+P-t-1);
}
}
for(int i=n-m+1;i<n;++i) ADD((1ll*a*i+b)%n,(1ll*a*i+b)%n);
sort(A+1,A+cnt+1); A[++cnt]=Data(n,0);
int now=0,res=0;
for(int i=1;i<=cnt;++i) {
if(A[i].p!=A[i-1].p&&!now) res+=A[i].p-A[i-1].p;
now+=A[i].w;
}
printf("%d\n",res);
return 0;
}