codeforces 727E. Games on a CD(双Hash

题目链接 http://codeforces.com/contest/727/problem/E  
题目大意 :有g个长度为k的互不相同的字符串,从中选择n个按照顺时针顺序写下形成一个环s。给出s(长度为n*k)和g个字符串,求是否有一种选择方案可以得到s(可以从任意位置开始)。 

数据范围:1 ≤ n ≤ 10^5, 1 ≤ k ≤ 10^5, n*k ≤ 10^6, n ≤ g ≤ 10^5, g*k ≤ 2*10^6


题解更详细版


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;
const int maxn =2e6 + 20;
const ll mod0 = 1e9 + 7,mod1 = 19260817;
map<P,int> dp;
set<int > S;
ll hash0[maxn],hash1[maxn],vis[maxn],seed = 31,A0[maxn],A1[maxn],G[maxn][2];
char str[maxn],str0[maxn];
int main(void)
{
    int n,k;
    cin>>n>>k;
    A0[0] = A1[0] = 1;
    for(int i = 1; i <= k; i ++) A0[i] = A0[i - 1] * seed % mod0,
    A1[i] = A1[i - 1] * seed % mod1;
    scanf("%s",str0);
    int len = n * k;
    for(int i = 0; i < len; i ++)
        str0[i + len] = str0[i];
    int g;
    cin>>g;
    for(int i =0 ; i < g; i ++)
    {
        scanf("%s",str);
        P p;
        for(int j = 0; j < k; j ++)
        {
            p.first = (p.first * seed + str[j] - 'a') % mod0;
            p.second = (p.second * seed + str[j] - 'a') % mod1;
        }
        dp[p] = i + 1;
    }
    for(int i =1 ;str0[i - 1]; i ++)
    {
        hash0[i] = (hash0[i - 1] * seed + str0[i - 1] - 'a') % mod0;
        hash1[i] = (hash1[i - 1] * seed + str0[i - 1] - 'a') % mod1;
    }
    for(int i =0 ; i < k; i ++)
    {
        for(int z = 1; z <= n; z ++) vis[z] = 0;
        S.clear();
        for(int j = 1; j <= n; j ++)
        {
            P p = P((hash0[j * k + i] - (hash0[(j - 1) * k + i] * A0[k] % mod0) + mod0) % mod0,
           (hash1[j * k + i] - (hash1[(j - 1) * k  + i] * A1[k] % mod1 ) + mod1) % mod1);
            vis[j] = dp[p];
            if(S.find(vis[j]) != S.end()) break;
            S.insert(vis[j]);
        }
        int Min = *min_element(vis + 1,vis + 1 + n);
        if(S.size() == n && Min)
        {
            cout<<"YES"<<endl;
            for(int j = 1; j <= n; j ++)
                cout<< vis[j]<<" ";
            return 0;
        }
    }
    cout<<"NO"<<endl;
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值