您的位置:首页 > 编程语言 > Go语言

BZOJ4377[POI2015] Kurs szybkiego czytania

2016-10-18 10:58 253 查看
BZOJ4377[POI2015] Kurs szybkiego czytania

Description

给定n,a,b,p,其中n,a互质。定义一个长度为n的01串c[0..n-1],其中c[i]==0当且仅当(ai+b) mod n < p。

给定一个长为m的小01串,求出小串在大串中出现了几次。

Input

第一行包含整数n,a,b,p,m(2<=n<=109,1<=p,a,b,m<n,1<=m<=106)。n和a互质。

第二行一个长度为m的01串。

Output

一个整数,表示小串在大串中出现了几次

Sample Input

9 5 6 4 3

101

Sample Output

3

HINT



Solution:

很有意思的一道题。

首先根据这个n与a互质,可以得出(ai+b)modn是[0,n)的一个全排列。

然后我们考虑小串的第i位与大串的某一位匹配了,设此点在大串中的值为x=(ai+b)%n。由于它满足于p的大小关系,可以列出一条式子:(假设小串第i位为0)

0≤x<p

设大串匹配的开头点的x值为x0,可以得到:(小串下标从1开始)

−a∗(i−1)%n≤(x−a∗(i−1))%n<(p−a∗(i−1))%n

即:

−a∗(i−1)%n≤x0<(p−a∗(i−1))%n

用同样的方式可以给出m条限制的式子,只需要求出这些的交集就可以了。但这并不好做,可以将所有的区间取个反,然后按左端点排序求补集大小,就可以了。

注意:上式取模取正后有可能出现左边大于右边的情况,这时其实两个符号之间是的关系。

还有一点:大串最后m−1个点也是不能作为x0的位置,要处理掉。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#define M 1000005
using namespace std;
struct Node{
int L,R;
bool operator <(const Node &a)const{
return L<a.L;
}
}Q[M<<2];
char str[M];
int main(){
int n,a,b,p,m,sz=0;
scanf("%d %d %d %d %d",&n,&a,&b,&p,&m);
scanf("%s",str);
for(int i=0;i<m;i++){
int L,R;
if(str[i]=='0'){//已取反
L=((p-1LL*a*i)%n+n)%n;
R=((n-1LL*a*i-1)%n+n)%n;
}else{
L=((0-1LL*a*i)%n+n)%n;
R=((p-1LL*a*i-1)%n+n)%n;
}
if(L<=R){
Q[++sz]=(Node){L,R};
}else{
Q[++sz]=(Node){0,R};
Q[++sz]=(Node){L,n-1};
}
}
for(int i=n-m+1;i<n;i++)//最后m-1位
Q[++sz]=(Node){(1LL*a*i+b)%n,(1LL*a*i+b)%n};
sort(Q+1,Q+sz+1);
int ed=-1,ans=0;
for(int i=1;i<=sz;i++){
if(ed<Q[i].L)ans+=Q[i].L-ed-1;
if(Q[i].R>ed)ed=Q[i].R;
}
printf("%d\n",ans+(n-1-ed));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: