4084: [Sdoi2015]双旋转字符串

来源:互联网 发布:债券行情软件 编辑:程序博客网 时间:2024/04/28 00:15

Description

给定两个字符串集合 S 和 T 。其中 S 中的所有字符串长度都恰好为 N ,而 T 中所有字符串长度都恰好为 M 。
且 N+M 恰好为偶数。如果记 S 中字符串全体为 S1,S2,…,STotalS ,而 T 中字符串全体为 T1,T2,…,TT
otalT 。现在希望知道有多少对

题解

hash 给大的集合中的每个字符串 把一段按mid分成两段 ,然后看看要是匹配的话需要小串是什么。。
然后需要的小串用个map记录一下就好了。。
最后累加很简单

CODE:

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<map>typedef long long LL;using namespace std;const int MOD=10037;//乘的东西const int MOD1=1000000007; const int N=4000005;int S,T,n,m,o;char ss[N],s1[N];LL shen[N];//前i为的hash值LL KK,KKK;map<int,int> q;struct qq{    int x;}s[N*2];int cnt=0;bool cmp (qq a,qq b){return a.x<b.x;}void add (){    cnt=0;    LL p1=0;    for (int u=1;u<=n-o;u++) p1=((p1*MOD)%MOD1+ss[u+o]-'a')%MOD1;    int len=0;    for (int u=1;u<=o;u++) s1[++len]=ss[u];    for (int u=1;u<=o;u++) s1[++len]=ss[u];    shen[0]=0;    for (int u=1;u<=len;u++) shen[u]=((shen[u-1]*MOD)%MOD1+s1[u]-'a')%MOD1;    for (int u=1;u<=o;u++)//枚举开头在哪里     {        LL a=((shen[u+n-o-1]-shen[u-1]*KKK%MOD1)%MOD1+MOD1)%MOD1;        if (a!=p1) continue;        a=((shen[u+o-1]-shen[u+n-o-1]*KK%MOD1)%MOD1+MOD1)%MOD1;        s[++cnt].x=(int)a;    }    sort(s+1,s+1+cnt,cmp);s[0].x=-1;    for (int u=1;u<=cnt;u++)        if (s[u].x!=s[u-1].x)            q[s[u].x]++;}int main(){    scanf("%d%d%d%d",&S,&T,&n,&m);o=(n+m)>>1;//中间端点是什么     KK=1;    for (int u=1;u<=2*o-n;u++) KK=KK*MOD%MOD1;    KKK=1;    for (int u=1;u<=n-o;u++) KKK=KKK*MOD%MOD1;    for (int u=1;u<=S;u++)    {        scanf("%s",ss+1);        add();    }    int ans=0;    for (int u=1;u<=T;u++)    {        scanf("%s",ss+1);        LL p=0;        for (int i=1;i<=m;i++) p=((p*MOD)%MOD1+ss[i]-'a')%MOD1;        ans=ans+q[p];    }    printf("%d\n",ans);    return 0;}