单词检索——题解

呃の,这题,真的不想说话。。

题目大意

给出N个由小写字母组成的字符串,统计至少在M个字符串中出现过的长度为L的字符串数
N,M<=2000,Li,L<=1000N,M<=2000,Li,L<=1000

一看,就知道是哈希——
对于每个长度为L的串,都哈希一下——还要记得O(1)O(1)推下一个哈希值,对于同一个模板中出现多次的字符串要记得去重

然后。。不要跟我说什么字符串哈希27进制更稳。。也不要说什么双大质数模数不会被卡。。反正我华丽丽地WAWA了一片,40分!

拼了命凑了一下午,生无可恋。。只能抄标程模数+26进制。。

只想说,100710……07绝对不是个好哈希模数!!!

PS:不想写哈希表,sort()+unique()sort()+unique()水过。。
上“凄凄惨惨戚戚”的代码:

#pragma GCC optimize(6) 
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const LL P1=499999999999993,P2=999973,PP=26;
int n,m,L,ans,T[2005];char s[1005];LL pow[2][1005];
struct ff{
    LL a,b;
    bool operator <(const ff y)const{return a<y.a||(a==y.a&&b<y.b);}
    bool operator ==(const ff y)const{return a==y.a&&b==y.b;}
    void clear(){a=b=0;}
}now,hsh[1005],all[2000005];
char gt(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
} 
int read(){
    int ret=0;char ch=gt();
    while(ch<'0'||ch>'9') ch=gt();
    while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=gt();
    return ret;
}
int main(){
    n=read(),m=read(),L=read();
    pow[0][0]=pow[1][0]=1;
    for(int i=1;i<=L;i++) pow[0][i]=pow[0][i-1]*PP%P1,pow[1][i]=pow[1][i-1]*PP%P2; //在Mod意义下的预处理
    for(int j=1;j<=n;j++){
        char ch=gt();int len=0;
        while(ch<'a'||ch>'z') ch=gt();
        while(ch>='a'&&ch<='z') s[++len]=ch-'a',ch=gt();
        if(len<L) continue;
        now.clear();
        for(int i=1;i<L;i++) now.a=(now.a*PP+s[i])%P1,now.b=(now.b*PP+s[i])%P2;
        for(int i=L;i<=len;i++){
            now.a=((now.a-pow[0][L-1]*s[i-L])%P1+P1)%P1,now.b=((now.b-pow[1][L-1]*s[i-L])%P2+P2)%P2;
            now.a=(now.a*PP+s[i])%P1,now.b=(now.b*PP+s[i])%P2;
            hsh[++T[j]]=now;
        }
        sort(hsh+1,hsh+1+T[j]),T[j]=unique(hsh+1,hsh+1+T[j])-hsh-1;
        for(int i=1;i<=T[j];i++) all[++T[0]]=hsh[i];
    }
    sort(all+1,all+1+T[0]);
    for(int i=1,j;i<=T[0];i=j){
        j=i+1;
        while(j<=T[0]&&all[j].a==all[i].a&&all[j].b==all[i].b) j++;
        ans+=(j-i>=m);
    }
    printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值