题意:有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. Django 发送邮件

    问题: 对于一些错误信息或用户注册账号的时候,需要给用户发送邮件进行验证. 以用户注册发邮件为例子,用户向后端提起注册,后端收到用户邮箱,对邮箱格式进行验证,然后发送邮件,邮件内容中包括邮件标题.邮件 ...

  2. linkin大话设计模式--建造模式

    linkin大话设计模式--建造模式 建造模式是对象的创建模式,可以讲一个产品的内部表象与产品的生成过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象. 建造模式的结构: 抽象建造者 ...

  3. MySQL查询结果复制到新表(更新、插入)

    MySQL中可以将查询结果复制到另外的一张表中,复制的话通常有两种情况,一种是更新已有的数据,另一种是插入一条新记录.下面通过例子来说明.首先构建两个测试表. 表t1: 表t2: 1.如果t2表中存在 ...

  4. PPT基础教程

    在当前演示文稿中增加新的幻灯片:快捷键>>ctrl+M  或者将鼠标定位到左侧窗格,然后按下回车键enter 母版??? 默认版式是"标题和文本"     右键 > ...

  5. 【转】sed 高级用法

    首先,应该明白模式空间的定义.模式空间就是读入行所在的缓存,sed对文本行进行的处理都是在这个缓存中进行的.这对接下来的学习是有帮助的. 在正常情况下,sed将待处理的行读入模式空间,脚本中的命令就一 ...

  6. Sql Server的艺术(五) SQL UNION与UNION JOIN运算符

    学习本节所用表: CREATE TABLE TEACHER ( ID INT IDENTITY (,) PRIMARY KEY , --主键,自增长 TNO INT NOT NULL, --教工号 T ...

  7. java中的二叉树排序问题

    原创:转载请注明出处 目的:想用java实现二叉树排序算法 思想:利用java中面向对象的思想,即: Tree:类 树根Tree:root //static所属于每一个Tree 左节点Tree:lef ...

  8. python爬虫(2)——编写一个爬虫

    一.URL的编码与解码 在python2中包含的urllib和urllib2,都是接受URL请求相关的模块.但是在python3中,却没有urllib2.实际上urllib2的功能在python3中可 ...

  9. qt中创建进程

    进程:1.QProcess 进程类 QProcess *a=new QProcess(); 2.启动void QProcess::start(const QString & command, ...

  10. Websocket原理及使用场景[转载]

    WebSocket的使用场景 社交聊天.弹幕.多玩家游戏.协同编辑.股票基金实时报价.体育实况更新.视频会议/聊天.基于位置的应用.在线教育.智能家居等需要高实时的场景 由轮询到WebSocket 1 ...