BZOJ4377[POI2015] Kurs szybkiego czytania

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

img

Solution:

很有意思的一道題。

首先根據這個na 互質,可以得出(ai+b)modn[0,n) 的一個全排列。

然後我們考慮小串的第i 位與大串的某一位匹配了,設此點在大串中的值爲x=(ai+b)%n 。由於它滿足於p 的大小關係,可以列出一條式子:(假設小串第i 位爲0)

0x<p

設大串匹配的開頭點的x 值爲x0 ,可以得到:(小串下標從1開始)
a(i1)%n(xa(i1))%n<(pa(i1))%n

即:
a(i1)%nx0<(pa(i1))%n

用同樣的方式可以給出m 條限制的式子,只需要求出這些的交集就可以了。但這並不好做,可以將所有的區間取個反,然後按左端點排序求補集大小,就可以了。

注意:上式取模取正後有可能出現左邊大於右邊的情況,這時其實兩個符號之間是的關係。

還有一點:大串最後m1 個點也是不能作爲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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章