题意:有n个单词,每个单词长度为k,顺时针将它们写成一个圆圈串。现在知道g个长度为k的单词,是否可以从这g个单词中选择n个形成这个圆圈串?如果有多个答案,任意输出一个。


思路

可以发现,如果枚举第一个串的开始位置,由于输入的g个串,长度都为k,那么每个串的位置就固定了。那么我只要知道,在主串上那一段位置的字符串,是否存在在g个串中,然后如果每个都存在,那么就是符合的。这一部分可以用字符串hash做到O(1)判断。

复杂度的话,枚举第一个串的复杂度是k,一共需要匹配n个字符串,所以总复杂度是O(nk)

要注意不能用自然溢出写,因为可以造出数据卡掉自然溢出,这里我是用双哈希写的。

字符串Hash

hash[i] = (hash[i-1]*p + idx(i)) % mod;

字符串子串Hash

hash[l,r] = (hash[r] - hash[l-1]*p^(r-l+1) + mod) % mod;

在这里,p和mod是两个质数。

AC代码

#include <cstdio>
#include <cmath>
#include <cctype>
#include <bitset>
#include <algorithm>
#include <cstring>
#include <utility>
#include <string>
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define eps 1e-10
#define inf 0x3f3f3f3f
#define pii pair<int, int>
typedef long long LL;
const double Pi = acos(-1.0);
const int maxn = 2e6 + 5;
const int seed = 1007;
const int mod[2] = {1000000007, 1000000009};
char s[maxn];
int Hash[2][maxn], ans[maxn];
int f[2][maxn], vis[maxn], tim;
map<pii, int>arr;

// hash[i] = (hash[i-1]*p + idx(i)) % mod;
// hash[l,r] = (hash[r] - hash[l-1]*p^(r-l+1)) % mod;

void init() {
    for(int i = 0; i < 2; ++i) {
        f[i][0] = 1;
        for(int j = 1; j < maxn; ++j) {
            f[i][j] = (LL)f[i][j-1] * seed % mod[i];
        }
    }
}

pii getHash(char *s) {
    int res[2] = {0, 0};
    int n = strlen(s);
    for(int i = 0; i < 2; ++i) {
        for(int j = 0; j < n; ++j) {
            res[i] = ((LL)res[i] * seed + s[j]) % mod[i];
        }
    }
    return pii(res[0], res[1]);
}

pii getHash(int l, int r) {
    int res[2];
    for(int i = 0; i < 2; ++i) {
        res[i] = (Hash[i][r] - (LL)Hash[i][l-1] * f[i][r-l+1] % mod[i] + mod[i]) % mod[i];
    }
    return pii(res[0], res[1]);
}

void getPre(char *s, int k) {
    int n = strlen(s+1);
    for(int i = 0; i < 2; ++i) {
        Hash[i][0] = 0;
        for(int j = 1; j <= n; ++j) {
            Hash[i][j] = ((LL)Hash[i][j-1] * seed + s[j]) % mod[i];
        }

        for(int j = n+1, t = 1; t < k ; ++t, ++j)
            Hash[i][j] = ((LL)Hash[i][j-1] * seed + s[t]) % mod[i];
    }
}

bool check(int st, int n, int k) {
    tim++;
    int l = st, r = st + k - 1;
    for(int i = 1; i <= n; i++, l += k, r += k) {
        pii p = getHash(l, r);
        if(!arr.count(p)) return 0;
        int val = arr[p];
        if(vis[val] == tim) return 0; //判重
        vis[val] = tim;
        ans[i] = val;
    }
    printf("YES\n");
    for(int i = 1; i <= n; ++i) {
        printf("%d%c", ans[i], i == n ? '\n' : ' ');
    }
    return 1;
}

int main() {
    init();
    int n, k;
    while(scanf("%d%d", &n, &k) == 2) {
        tim = 1;
        arr.clear();
        scanf("%s", s+1);
        getPre(s, k);
        int g;
        scanf("%d", &g);
        for(int i = 1; i <= g; ++i) {
            scanf("%s", s);
            pii p = getHash(s);
            arr[p] = i;
        }
        bool ok = 0;
        for(int i = 1; i <= k; ++i) {
            if(check(i, n, k)) {
                ok = 1;
                break;
            }
        }
        if(!ok) printf("NO\n");
    }
    return 0;
}

如有不当之处欢迎指出!

CodeForces - 727E Games on a CD 字符串Hash的更多相关文章

  1. 【codeforces 514C】Watto and Mechanism(字符串hash)

    [题目链接]:http://codeforces.com/contest/514/problem/C [题意] 给你n个字符串; 然后给你m个询问;->m个字符串 对于每一个询问字符串 你需要在 ...

  2. 【题解】 Codeforces Edu44 F.Isomorphic Strings (字符串Hash)

    题面戳我 Solution 我们按照每个字母出现的位置进行\(hash\),比如我们记录\(a\)的位置:我们就可以把位置表示为\(0101000111\)这种形式,然后进行字符串\(hash\) 每 ...

  3. Codeforces 898F - Restoring the Expression(字符串hash)

    898F - Restoring the Expression 思路:字符串hash,base是10,事实证明对2e64取模会T(也许ull很费时),对1e9+7取模. 代码: #include< ...

  4. 【CodeForces727E/CF727E】Games on a CD (字符串哈希)

    题目: CodeForces727E 分析: 看到字符串比较,肯定想到哈希啊--现学的哈希,先丢两个重要的公式 (\(seed\)是大于字符集大小的质数,\(p\)是大质数) \[hash[i]=(h ...

  5. CodeForces 1056E - Check Transcription - [字符串hash]

    题目链接:https://codeforces.com/problemset/problem/1056/E One of Arkady's friends works at a huge radio ...

  6. codeforces gym 101164 K Cutting 字符串hash

    题意:给你两个字符串a,b,不区分大小写,将b分成三段,重新拼接,问是否能得到A: 思路:暴力枚举两个断点,然后check的时候需要字符串hash,O(1)复杂度N*N: 题目链接:传送门 #prag ...

  7. 线段树 + 字符串Hash - Codeforces 580E Kefa and Watch

    Kefa and Watch Problem's Link Mean: 给你一个长度为n的字符串s,有两种操作: 1 L R C : 把s[l,r]全部变为c; 2 L R d : 询问s[l,r]是 ...

  8. 洛谷P3234 抄卡组 [HNOI2014] 字符串hash

    正解:字符串hash 解题报告: 传送门! 字符串hash是字符串匹配中很常见的一个方法,原理也很好懂,这里就不做太多阐述辣有时间放到hash笔记里面去QAQ 题意不说了挺好理解的,自带一句话概括好评 ...

  9. [知识点]字符串Hash

    1.前言 字符串的几大主要算法都多少提及过,现在来讲讲一个称不上什么算法, 但是非常常用的东西——字符串Hash. 2.Hash的概念 Hash更详细的概念不多说了,它的作用在于能够对复杂的状态进行简 ...

随机推荐

  1. python_如何在循环引用中管理内存?

    案例: python中通过引用计数来回收垃圾对象,在某些环形数据结构(树,图--),存在对象间的循环引用,比如树的父节点引用子节点,子节点同时引用父节点,此时通过del掉引用父子节点,两个对象不能被立 ...

  2. Windows脚本修改主机名-不重启

    windows通过脚本方式修改主机名的方法有很多种,下面介绍修改注册表方式的脚本. 使用方法: 1 打开cmd,假如脚本名为ModifyHostname.bat 2 执行脚本,并加入脚本参数,其中第一 ...

  3. Linux指令--nl

    原文出处:http://www.cnblogs.com/peida/archive/2012/11/01/2749048.html nl命令在linux系统中用来计算文件中行号.nl 可以将输出的文件 ...

  4. mysql 列转行,合并字段

    数据表: 列转行:利用max(case when then) max---聚合函数 取最大值 (case course when '语文' then score else 0 end) ---判断   ...

  5. 【php】phpExcel使用教程,如何导出excel表格

    [1]下载phpExcel类文件 可在官方去下载 我们只需要classes中的文件,把Classes文件复制到项目中 只需要2个文件就可以了  一个就是phpExcel(刚才我们复制过来的文件 Cla ...

  6. iozone测试磁盘性能

    什么是iozone? iozone是一个文件系统的benchmark工具,可以测试不同的操作系统中文件系统的读写性能. 可以测试 Read, write, re-read,re-write, read ...

  7. JS声明变量的写法

    学习JS时候,声明变量是必须的,(虽然在没有声明变量的情况下,对某一变量赋值后, js自动认为已进行声明,但为了严谨,建议还是要进行声明)声明方式有传统的 var a: var b: var c: 也 ...

  8. 蓝桥杯练习系统—基础练习 sine之舞

    题目:最近FJ为他的奶牛们开设了数学分析课,FJ知道若要学好这门课,必须有一个好的三角函数,所以他准备和奶牛们做一个"Sine之舞"的游戏,寓教于乐,提高奶牛们的计算能力. 不妨设 ...

  9. PyCharm运行Nosetests并导出测试报告

    1. Pycharm运行Nosetests PyCharm可以使用两种方法,运行Nosetests测试文件: 1) 图形用户界面GUI a) 在PyCharm中,选中测试文件,如Tests/test_ ...

  10. bzoj 4033: [HAOI2015]树上染色 [树形DP]

    4033: [HAOI2015]树上染色 我写的可是\(O(n^2)\)的树形背包! 注意j倒着枚举,而k要正着枚举,因为k可能从0开始,会使用自己更新一次 #include <iostream ...