题意:有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. windows的三种内存管理方法

    Windows的内存管理方法 windows提供了3种方法来进行内存管理: l         虚拟内存,最适合用来管理大型对象或者结构数组 l         内存映射文件,最适合用来管理大型数据流 ...

  2. js 抛物线 笔记备份

    var funParabola = function(element, target, options) { /* * 网页模拟现实需要一个比例尺 * 如果按照1像素就是1米来算,显然不合适,因为页面 ...

  3. linkinFrame--测试项目添加git管理

    OK,前面一篇博客,已经搭建好了项目的基础的结构.现在我们添加一个简单的servlet来测试下项目能不能跑,然后在讲项目添加到coding上用git管理. 1,我们编写一个servlet,编写一个js ...

  4. MS SQL 模仿ORACLE的DESC

    前言: 在ORACLE数据库的SQL*PLUS里面有个DES(DESCRIBE)命令,它可以返回数据库所存储对象的描述,如下所示 SQL> DESC STUDENT_SCORE   Name T ...

  5. C# Linq基本常用用法

    1.什么是Linq? Lanaguage Interated Query(语言集成查询),Linq 是集成C# 和VB这些语言中用于提供数据查询能力的一个新特性. 这里只介绍两种基本常用用法. 学习方 ...

  6. Spring Cache For Redis

    一.概述 缓存(Caching)可以存储经常会用到的信息,这样每次需要的时候,这些信息都是立即可用的. 常用的缓存数据库: Redis   使用内存存储(in-memory)的非关系数据库,字符串.列 ...

  7. Win10图片打开方式没有“Windows照片查看器”,如何找回?

    如果你是全新安装的Win10正式版,那么就会发现当在图片上点击右键时,"打开方式"菜单里熟悉的"Windows照片查看器"不见了,换成了Win10全新的&quo ...

  8. C语言预处理 编译 汇编 链接四个阶段

    c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接. 编译过程 编译过程又可以分成两个阶段:编译和会汇编. 编译 编译是读取源程序(字符流),对之进行词法和语法的分析,将高 ...

  9. mongodb备份恢复,数据导入导出

    数据导出 mongoexport 假设库里有一张apachelog表,里面有2 条记录,我们要将它导出 /test/mongodb/bin/mongo use wxdata switched to d ...

  10. Java程序占用的内存可能会大于Xmx

    很多人认为Xmx和-Xms参数指定的就是Java程序将会占用的内存,但是这实际上只是Java堆对象将会占用的内存.堆只是影响Java程序占用内存数量的一个因素. 除了堆,影响Java程序所占用内存的因 ...