D. Tavas and Malekas DFS模拟 + kmp + hash || kmp + hash
http://codeforces.com/contest/535/problem/D
如果真的要把m个串覆盖上一个串上面,是可以得,不会超时。
要注意到一点,全部覆盖后再判断时候合法,和边放边判断,结果是一样的,后者还更难做到。
那么就是先按顺序把串覆盖上去,已经存在的就不去覆盖了,然后kmp一次记录匹配位置,判断即可。
用DFS覆盖,DFS回溯的时候记录一个数组tonext[i]表示第i个点的第一个空位是tonext[i],这样覆盖上去就是O(n)
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <assert.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> const int maxn = 1e6 + 20; const int MOD = 1e9 + 7; int tonext[maxn]; int ret; char str[maxn]; char sub[maxn]; void dfs(int cur, int k, int from) { if (k < 0) return; if (k == 0) { ret = cur; return; } if (tonext[cur] != cur) { ret = tonext[cur]; dfs(tonext[cur], k - (tonext[cur] - cur), from + tonext[cur] - cur); tonext[cur] = ret; } else { ret = cur + 1; str[cur] = sub[from]; dfs(cur + 1, k - 1, from + 1); tonext[cur] = ret; } } int a[maxn]; bool HASH[maxn]; int kmpnext[maxn]; void get_next(char sub[], int lensub) { int i = 1, j = 0; kmpnext[1] = 0; while (i <= lensub) { if (j == 0 || sub[i] == sub[j]) { kmpnext[++i] = ++j; } else j = kmpnext[j]; } return; } void kmp(int lenstr, int lensub) { int i = 1, j = 1; while (i <= lenstr) { if (j == 0 || str[i] == sub[j]) { ++i; ++j; } else j = kmpnext[j]; if (j == lensub + 1) { HASH[i - lensub] = true; j = kmpnext[j]; } } return; } void work() { int lenstr, m; scanf("%d%d", &lenstr, &m); for (int i = 1; i <= lenstr; ++i) { tonext[i] = i; str[i] = 'A'; // printf("f"); } // printf("%c\n", str[1]); scanf("%s", sub + 1); int lensub = strlen(sub + 1); for (int i = 1; i <= m; ++i) { scanf("%d", &a[i]); dfs(a[i], lensub, 1); } str[lenstr + 1] = '\0'; // printf("%s\n", str + 1); get_next(sub, lensub); kmp(lenstr, lensub); for (int i = 1; i <= m; ++i) { if (!HASH[a[i]]) { cout << 0 << endl; return; } } LL ans = 1; for (int i = 1; i <= lenstr; ++i) { if (str[i] == 'A') { ans *= 26; if (ans >= MOD) ans %= MOD; } } cout << ans << endl; } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif work(); return 0; }
开始的时候想不到直接kmp
用的其实就是kmp的next数组,不断next[next[]]
就是记录所有的前缀和后缀相等。
对于abc****abc,也就是前后缀相等的话,长度是3
记上一个覆盖到的位置是pos[i - 1] + lensub - 1
然后如果这个和他没交集,就算,如果有,要判断。怎么判断呢?
算出交集大小,如果交集刚好是3,那么是可以得。否则,是NO
交集是3说明后缀的那3个和前缀匹配了。
注意m可能是0
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <assert.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> const int maxn = 1e6 + 20; const int MOD = 1e9 + 7; char sub[maxn]; int tonext[maxn]; int pos[maxn]; bool book[maxn]; void get_next(char sub[], int lensub) { int i = 1, j = 0; tonext[1] = 0; while (i <= lensub) { if (j == 0 || sub[i] == sub[j]) { tonext[++i] = ++j; } else j = tonext[j]; } return; } void work() { int lenstr, m; // cin >> lenstr >> m; // cin >> sub + 1; scanf("%d%d", &lenstr, &m); scanf("%s", sub + 1); int lensub = strlen(sub + 1); get_next(sub, lensub); for (int i = 1; i <= m; ++i) { // cin >> pos[i]; scanf("%d", &pos[i]); } int t = tonext[lensub + 1]; while (t != 1) { book[t - 1] = true; t = tonext[t]; } int total = lenstr - lensub; if (m == 0) { total += lensub; } for (int i = 2; i <= m; ++i) { int to = pos[i - 1] + lensub - 1; int haha = to - pos[i] + 1; if (haha <= 0) { total -= lensub; continue; } if (!book[haha]) { printf("0\n"); return; } total -= lensub - haha; } LL ans = 1; for (int i = 1; i <= total; ++i) { ans *= 26; if (ans >= MOD) ans %= MOD; } printf("%I64d\n", ans); } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif work(); return 0; }
既然选择了远方,就要风雨兼程~
posted on 2016-12-08 15:30 stupid_one 阅读(157) 评论(0) 编辑 收藏 举报