洛谷 P8085 [COCI2011-2012#4] KRIPTOGRAM
思路
注意到只要字符串出现的相对位置匹配就行。设 分别为明文/密文中第 个字符串与上一个跟它相同的字符串隔了几个单词(若该字符串第一次出现则设为 )。然后直接 KMP。注意可能有这种情况:明文为 c (a b c)
、密文为 x y z
,此时 ,但 。因此还要特判 的情况,即如果 且 时就能匹配。
代码
code
/* p_b_p_b txdy AThousandMoon txdy AThousandSuns txdy hxy txdy */ #include <bits/stdc++.h> #define pb push_back #define fst first #define scd second using namespace std; typedef long long ll; typedef pair<ll, ll> pii; const int maxn = 1000100; const int inf = 0x3f3f3f3f; map<string, int> mp; int n, m, a[maxn], b[maxn], fail[maxn]; void solve() { string s; while (cin >> s) { if (s[0] == '$') { break; } ++n; if (mp.find(s) == mp.end()) { a[n] = inf; mp[s] = n; } else { a[n] = n - mp[s]; mp[s] = n; } } mp.clear(); while (cin >> s) { if (s[0] == '$') { break; } ++m; if (mp.find(s) == mp.end()) { b[m] = inf; mp[s] = m; } else { b[m] = m - mp[s]; mp[s] = m; } } for (int i = 2, j = 0; i <= m; ++i) { while (j && b[i] != b[j + 1]) { j = fail[j]; } if (b[i] == b[j + 1]) { ++j; } fail[i] = j; } for (int i = 1, j = 0; i <= n; ++i) { while (j && ((b[j + 1] == inf && a[i] < j + 1) || (b[j + 1] != inf && b[j + 1] != a[i]))) { j = fail[j]; } if (!((b[j + 1] == inf && a[i] < j + 1) || (b[j + 1] != inf && b[j + 1] != a[i]))) { ++j; } // printf("%d %d\n", i, j); if (j == m) { printf("%d\n", i - m + 1); return; } } } int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int T = 1; // scanf("%d", &T); while (T--) { solve(); } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】