1. 程式人生 > 實用技巧 >NOIp2020 T2 字串匹配 題解

NOIp2020 T2 字串匹配 題解

NOIp2020 T2 字串匹配 題解

題目大意

定義\(A^1 = A\), \(A^i=A^{i-1}A\) ,如\(A=abc\)\(A^{3}=abcabcabc\)

定義\(f(S)\)為字串\(S\)中出現奇數次的字元的數量,如\(A=abbc\),\(f(A)=2\)

給定\(S\),求滿足\(S=(AB)^iC\)\(f(A)\le f(C)\)的方案數

題解(kmp)

首先我們需要知道一個東西

最小迴圈元長度 \(len = i - nxt[i]\) (\(nxt[i]\)為kmp中求出的失配陣列,具體是為什麼,自己想想,顯而易見)

於是我們從二開始列舉 \(i\) ,只要現在列舉到的\(S\)

的最小迴圈元長度\(len\)\(|S|\)的約數,則\(S\)一定可以表示為\((AB)^k\)的形式,此時,我們可以用 \(k=i \bmod len\)求出\(AB\)串迴圈次數\(k\).

先預處理出每個\(C\)中出現奇數次的字元數,時間複雜度\(O(n)\),還得跑一次kmp,求出\(nxt\)陣列,時間複雜度\(O(n)\)

考慮列舉\(AB\)串長度.

\(S=ABC\)的情況統計答案

然後重複\(AB\)串,對於每個\(S=(AB)^jC\)的情況,如果符合要求,累加答案,否則顯而易見,若\(S!=(AB)^iC\)\(S!=(AB)^{i+1}C\)必成立,退出迴圈即可.

總複雜度為\(O(Tn(26+1/n+2/n+...+n/n)) = O(T(nlogn + 26n))\)

需要注意的

  • 列舉 \(AB\) 串長度從\(2\)-> \(n-1\).

  • 統計答案時,所有滿足\(f(A') \le f(C)\)的串\(A'\)都會有\(1\)的貢獻,所以我們可以陣列\(c[p]\)表示當現在\(f(C)=p\)時,有多少個\(A'\)滿足條件.可以用以下方法\(O(26)\)複雜度求出

    for(int i = tmp; i <= 26; ++i) c[i]++; // tmp 表示從現在A串中出現奇數次的字元的數量
    
  • 重複\(AB\)串可以用以下方法求出

    for (int j = i * 2; j < n; j += i) { // i為列舉的AB串長度
    	if(i % (j - nxt[j]) == 0 && j / (j - nxt[j]) > 1) {
    		ans += c(tot[j + 1]);
    	} else break;
    }
    

題解(hash)

和kmp的只有判斷\(S=(AB)^iC\)是否成立時不同.判斷方法如下

for (int j = i * 2; j < n; j += i) { // i為列舉的AB串長度
	if((f[j] - f[j - i] * pw[i] % mod + mod) % mod == f[i]) {
		ans += c(tot[j + 1]);
	} else break;
} // f[x]表示從1到x的字串的hash結果  pw[x]表示hash的底數如131,1331的x次結果  mod為一個大質數

總複雜度\(O(T(26n+nlogn))\)但常數略大

題解(exkmp) -- 標準\(O(n)\)做法

不會,以後學了再補.