列表

详情


NC20371. [SDOI2015]双旋转字符串

描述

给定两个字符串集合 S 和 T 。其中 S 中的所有字符串长度都恰好为 N ,而 T 中所有字符串长度都恰好为 M 。且 N+M 恰好为偶数。 
如果记 S 中字符串全体为 S1,S2,...,STotalS ,而 T 中字符串全体为 T1,T2,...,TTotalT 。 现在希望知道有多少对 < i,j > ,满足将 Si 和 Tj 拼接后得到的字符串 Si+Tj 满足双旋转性。
一个长度为偶数字符串 W 可以表示成两段长度相同的字符串的拼接,即 W=U+V。如果 V 可以通过 U 旋转得到,则称 W 是满足双旋转性的。
比如说字符串 U=“vijos”可以通过旋转得到“ijosv”,“josvi”,“osvij” 或“svijo”。那么“vijosjosvi”就是满足双旋转性的字符串。

输入描述

第一行输入四个正整数,分别为 TotalS,TotalT,N 和 M,依次表示集合 S 的大小,集合 T 的大小,集合 S 中字符串的长度和集合 T 中字符串的长度。
之后 TotalS 行,依次给出 S 中所有的字符串 Si,1 ≤ i ≤ TotalS。保证每一个字符串长度都恰为 N ,且字符串只由 26 个小写字母组成。
之后 TotalT 行,依次给出 T 中所有的字符串 Ti,1 ≤ i ≤ TotalT。保证每一个字符串长度都恰为 M ,且字符串只由 26 个小写字母组成。
1 ≤ N ≤ 100;1 ≤ M ≤ 100;1 ≤ TotalS ≤ 100;1 ≤ Total^T ≤ 100,2 ≤ N*TotalS+M*TotalT ≤ 4×10^6,N ≥ M

输出描述

输出一个整数,表示满足要求的数字对 < i,j > 有多少个。

示例1

输入:

4 4 7 3 
vijosvi 
josvivi 
vijosos 
ijosvsv 
jos 
vij 
ijo 
jos

输出:

6

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 529ms, 内存消耗: 5420K, 提交时间: 2020-05-21 13:44:25

#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;
}

C++14(g++5.4) 解法, 执行用时: 596ms, 内存消耗: 5844K, 提交时间: 2020-03-30 17:21:27

#include <bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int MX=4e6+9;
const int base=131;
char s[MX],t[MX];
int n,m,ls,lt,mid;
ull has[MX],bas[MX];
map<ull,int> mp;

ull get(int l,int r){
    if( l==0 )
        return has[r];
    else
        return has[r]-has[l-1]*bas[r-l+1];
}

void inst(){
    char s1[MX];
    for( int i=0 ; i<mid ; i++ )
        s1[i]=s1[i+mid]=s[i];
    has[0]=s1[0]-'a'+1;
    for( int i=1 ; i<2*mid ; i++ )
        has[i]=has[i-1]*base+s1[i]-'a'+1;
    int len=ls-mid;
    ull pos=0;
    for( int i=mid ; i<ls ; i++ )
        pos=pos*base+s[i]-'a'+1;
    for( int i=0 ; i<mid ; i++ ){
        ull po=get(i,i+len-1);
        if( po==pos ){
            int l=i+len,r=l+mid-len-1;
            mp[get(l,r)]++;
        }
    }

}

int main()
{
  //  freopen("input.txt","r",stdin);
    scanf("%d %d %d %d",&n,&m,&ls,&lt);
    bas[0]=1;
    for( int i=1 ; i<=ls+lt ; i++ )
        bas[i]=bas[i-1]*base;
    mid=(ls+lt)>>1;
    for( int i=1 ; i<=n ; i++ ){
        scanf("%s",s);
        inst();
    }
    int ans=0;
    for( int i=1 ; i<=m ; i++ ){
        scanf("%s",t);
        ull pos=0;
        for( int i=0 ; i<lt ; i++ )
            pos=pos*base+t[i]-'a'+1;
        if( mp.count(pos) )
            ans+=mp[pos];
    }
    printf("%d\n",ans);
    return 0;
}

上一题