《浪漫沙加開拓者重製版》銷量超預期後續作品有望重製
阿新 • • 發佈:2021-06-25
快速讀入
可以根據題目描述自行修改。
void Init() { char ch; ch = getchar(); while (ch < 'A' || ch > 'Z') ch = getchar(); while (ch >= 'A' && ch <= 'Z') { A[++lena] = ch; ch = getchar(); } while (ch < 'A' || ch > 'Z') ch = getchar(); while (ch >= 'A' && ch <= 'Z') { B[++lenb] = ch; ch = getchar(); } }
KMP
\(A\) 為大串,\(B\) 為小串。
求 \(next\) 陣列
void make_nxt()
{
j = 0;
for (int i = 2; i <= lenb; ++i)
{
while (B[i] != B[j + 1] and j)
j = nxt[j];
if (B[i] == B[j + 1])
++j;
nxt[i] = j;
}
}
匹配
void check() { j = 0; for (int i = 1; i <= lena; i++) { while (A[i] != B[j + 1] and j) j = nxt[j]; if (A[i] == B[j + 1]) ++j; if (j == lenb) { printf("%lld\n", i - lenb + 1); j = nxt[j]; } } }
題目詳解
P4391 [BOI2009]Radio Transmission
觀察題目性質,可得:\(ans=n-nxt[n]\)。
直接切
int main()
{
n = read();
for (int i = 1; i <= n; ++i)
B[i] = getchar();
make_nxt();
printf("%lld\n", n - nxt[n]);
}
P3435 [POI2006]OKR-Periods of Words
題意簡述:
對於給定串的每個字首 \(i\),求最長的,使這個字串重複兩邊能覆蓋原字首 \(i\)
分析:
利用 \(next\) 的性質:字首 \(i\) 的長度為 \(next[i]\) 的字首和字尾是相等的
如果有 \(i\) 一個公共前後綴長度為 \(j\),那麼這個字首 \(i\) 就有一個週期為 \(i-j\)。
做法:
先求出 \(next\) 陣列
對於每個字首 \(i\),令 \(j=i\),然後在 \(j>0\) 的情況下令 \(j=next[j]\),最小的 \(j\) 就是答案,此時 \(ans+=i−j\)。
一個優化:求出 \(j\) 以後,令 \(j=fail[i]\),這樣能加快遞迴速度(相當於記憶化了)
const ll N = 1e7 + 2;
ll n, nxt[N];
char B[N];
void make_nxt()
{
ll k = 1;
for (ll i = 2; i <= n; ++i)
{
while ((B[k] != B[i] && k > 1) || k > i)
k = nxt[k - 1] + 1;
if (B[k] == B[i])
nxt[i] = k++;
}
}
ll ans = 0;
int main()
{
// freopen("P3435_1.in", "r", stdin);
n = read();
for (ll i = 1; i <= n; ++i)
cin >> B[i];
make_nxt();
for (ll i = 1; i <= n; ++i)
{
ll j = i;
while (nxt[j])
j = nxt[j];
if (nxt[i])
nxt[i] = j;
ans += 1LL * (i - j);
}
printf("%lld\n", ans);
}
P4824 [USACO15FEB]Censoring S
\(\text{KMP}\) 的刪除操作。
在匹配過程中,如果匹配成功了,就將子串 \(B\) 刪除,可以證明,對之前不會產生影響。
刪了再加入,類似棧的操作,因此用棧維護上述操作過程中的字串即可。
時間複雜度:\(B\) 自身匹配一次 \(+A\) 與 \(B\) 匹配一次 \(+A\) 中最多每個字元進出棧一次,為 \(O(∣A∣)\)
const ll N = 10000003;
ll k, lena, lenb, nxt[N];
char A[N], B[N];
int stk[N], top, pos[N];
void Init()
{
char ch;
ch = getchar();
while (ch < 'a' || ch > 'z')
ch = getchar();
while (ch >= 'a' && ch <= 'z')
{
A[++lena] = ch;
ch = getchar();
}
while (ch < 'a' || ch > 'z')
ch = getchar();
while (ch >= 'a' && ch <= 'z')
{
B[++lenb] = ch;
ch = getchar();
}
}
void make_nxt()
{
k = 1;
for (int i = 2; i <= lenb; ++i)
{
while ((B[k] != B[i] && k > 1) || k > i)
k = nxt[k - 1] + 1;
if (B[k] == B[i])
nxt[i] = k++;
}
}
void check()
{
k = 0;
for (int i = 1; i <= lena; ++i)
{
while (B[k + 1] != A[i] && k > 0)
k = nxt[k];
if (B[k + 1] == A[i])
k++;
pos[i] = k;
stk[++top] = i;
if (k == lenb)
{
top -= lenb;
k = pos[stk[top]];
}
}
}
int main()
{
Init();
make_nxt();
check();
for (int i = 1; i <= top; ++i)
printf("%c", A[stk[i]]);
Edison Ba;
}