Codeforeces 727 E 字符串双Hash 2017/1/12
来源:互联网 发布:改良圈算法 matlab 编辑:程序博客网 时间:2024/05/04 01:18
题目链接:见这里
题意:n个长度为k的字符串,首尾相接,按顺时针顺序写在一张CD上,每个字符串只写一次总字符串长度小于1e6。保证每个字符串不同。这样CD上就有了一个环形字符串,长度是n*k。又给出g个长度为k的字符串列表(编号从1到g),按照顺时针打印CD上字符串的编号。保证每个字符串不同。保证这g个字符串长度的和小于2*1e6。
下面代码和思路参考了Wannafly每日一题,顺便学会了Hash。记录了模板。
解题思路:可以发现,如果枚举第一个串的开始位置,由于输入的g个串,长度都为k,那么每个串的位置就固定了。那么我只要知道,在主串上那一段位置的字符串,是否存在在g个串中,然后如果每个都存在,那么就是符合的。这一部分可以用字符串hash做到O(1)判断。复杂度的话,枚举第一个串的复杂度是k,一共需要匹配n个字符串,所以总复杂度是O(nk)。要注意不能用自然溢出写,因为可以造出数据卡掉自然溢出。
代码如下:
#include <bits/stdc++.h>using namespace std;typedef long long LL;typedef pair <int, int> pii;const int N = 2e6 + 5;const int seed = 131;int mod[2] = {1000000007, 1000000009};char S[N]; //输入字符串int F[2][N]; //seed ^ aint pre[2][N];int n, g, w;int tim, vis[N], ans[N];map <pii, int> cnt;void pre_init(){ //deal with seed ^ n for(int t = 0; t <= 1; t++){ F[t][0] = 1; for(int i = 1; i < N; i++){ F[t][i] = (LL)F[t][i-1] * seed % mod[t]; } }}pii Hash(string s){ //Hash a string int ret[2] = {0}; int len = s.size(); for(int t = 0; t <= 1; t++){ for(int i = 0; i < len; i++){ ret[t] = ((LL) ret[t] * seed + s[i]) % mod[t]; } } return pii(ret[0], ret[1]);}pii Hash(int l, int r){ int ret[2]; for(int t = 0; t <= 1; t++){ ret[t] = (pre[t][r] - (LL)pre[t][l-1] * F[t][r-l+1] % mod[t] + mod[t]) % mod[t]; } return pii(ret[0], ret[1]);}void pre_solve(){ int len = strlen(S + 1); for(int t = 0; t <= 1; t++){ pre[t][0] = 0; for(int i = 1; i <= len; i++){ pre[t][i] = ((LL)pre[t][i-1] * seed + S[i]) % mod[t]; } for(int j = len + 1, i = 1; i <= w - 1; i++, j++){ pre[t][j] = ((LL)pre[t][j-1] * seed + S[i]) % mod[t]; } }}bool check(int id){ tim++; int l = id, r = id + w - 1; for(int i = 1; i <= n; i++, l += w, r += w){ pii t = Hash(l, r); if(!cnt.count(t)) return 0; //目标串中没有这个子串 int p = cnt[t]; if(vis[p] == tim) return 0; //目标串出现了大于1次 vis[p] = tim; ans[i] = p; } printf("YES\n"); for(int i = 1; i <= n; i++) cout << ans[i] <<" "; cout << endl; return 1;}int main(){ pre_init(); scanf("%d%d%s", &n, &w, S+1); pre_solve(); scanf("%d", &g); for(int i = 1; i <= g; i++){ scanf("%s", S); pii t = Hash(S); cnt[t] = i; } bool mark = 0; for(int i = 1; i <= w; i++){ if(check(i)){ mark = 1; break; } } if(mark == 0){ printf("NO\n"); } return 0;}
0 0
- Codeforeces 727 E 字符串双Hash 2017/1/12
- Codeforeces 727 E 字符串双Hash 2017/1/12
- CodeForeces 25E (kmp)
- codeforeces 344 E Read Time
- Codeforeces
- Codeforeces 342E 对操作分块
- [字符串Hash DP] Codeforces 613E #339 (Div. 1) E. Puzzle Lover
- Codeforces 25E 字符串hash模板题
- codeforces 727E. Games on a CD(双Hash
- [Codeforeces 894E. Ralph and Mushrooms] 缩点+拓扑
- POJ3461 字符串双HASH
- POJ3461 字符串双HASH
- 【线段树+字符串hash】 codeforces 213E Two Permutations
- codeforces 321# E. Kefa and Watch (线段树+字符串hash)
- codeforces 580 E. Kefa and Watch (字符串hash + 线段树)
- codeforces #336 E. Marbles (字符串hash或者kmp匹配)
- Codeforces Round #321 (Div. 2)E 线段树+字符串hash
- 字符串hash
- 奥斯丁佩伊州立大学Graduation 奥斯丁佩伊州立大学CertifiCate
- c# winform 利用 windows media player 循环播放视频
- 贝尔蒙特大学Graduation 贝尔蒙特大学CertifiCate
- 伯特利学院Graduation 伯特利学院CertifiCate
- AsyncTask异步任务
- Codeforeces 727 E 字符串双Hash 2017/1/12
- 布莱恩学院Graduation 布莱恩学院CertifiCate
- Pentester Lab学习计划之Web for Pentester II
- Jacobi Gauss-Seidel迭代法
- 卡森纽曼学院Graduation 卡森纽曼学院CertifiCate
- CSS中那些px、em、pt、rem、%、dp(android)单位
- 方格问题
- 结构体 共用体 枚举
- 【JVM】配置jvm内存