NOIP2020 字串匹配

2022-03-06 13:38:01 字數 1921 閱讀 8650

推薦一篇我覺得很好理解的部落格

首先考慮暴力:令 \(t=ab\),從小到大列舉 \(t\) 的長度,找到最短的 \(c_1\) ,列舉有多少個 \(t\) 的真字首 \(a\) 滿足 \(f(a) \leqslant f(c_1)\),

之後令 \(c_2=abc\),再令$ c_3=ababc$……以此類推

考慮優化。結合上面的暴力分析,容易想到 \(f(c_k)\) 的前面的所有 \(abab\)均不會對其產生貢獻,故有 \(f(c_)=f(c_1)\), \(f(c_)=f(c_2)\)

所以,$ a\(,\)b\(,\)c$ 是一組解就意味著 \(a\),\(b\),\(ababc\)也是一組解(如果 \(ab\) 的重複次數 \(\geqslant 3\)),

那麼我們無需列舉所有的 \(c_k\),而只需計算 \(c_1\) 與 \(c_2\) 解的數量,再分別乘上有多少$ c_k$ 與其相同即可

最後我們發現時間複雜度的瓶頸在於找到最短的 \(c\),看出這個問題本質是求 \(t\) 的最大重複次數,使用字串 \(hash\) 即可

此演算法是 \(n (\ln n+\log_2 26)\)的

——以上均摘自開頭說的部落格em

求\(c_1\)

\(c_2\)的解的數量, 我們只需要找到\(t\)的真字首中有多少個滿足條件的即可 應該...能想到用樹狀陣列來維護叭

對於字串\(s\)的每個字尾的 出現奇數次的字母的數量 我們也可以提前處理出來 這樣就能很快確定c的

出現奇數次的字母的數量啦

#include using namespace std;

#define ll long long

const int n = 1 << 20 + 5;

ll n, ans, jcnt;//jcnt代表當前有多少個奇數次的字元數

char s[n];

ll bit[30];//bit[i]代表有字串s有多少個的字首有不超過i個奇數次的字元的數量

ll discnt[n];//discnt[i]表示s[i - n]有的多少個奇數次的字元的數量

bool isj[30], disj[30];//isj[1 - 26]分別表示a - z的數量是否為奇數次, disj意義相同,只不過是倒序的

unsigned long long h[n], p;//h: 雜湊值

int lowbit(int x)

void add(int x)

}ll ask(int x)

return sum;

}int main()

for(int i = 1; i <= len; i++)

h[i] = h[i - 1] * 233 + s[i];

add(1);

jcnt = 1;

isj[s[1] - 'a'] = 1;

for(int i = 2; i < len; i++)

if(x * i == len) ans += bit[1] * ((x - 1) / 2);//當x * i == len時c不能是空串所以最短的c應該是abab, 會比其他的情況少一種

else ans += ask(discnt[x * i + 1]) * ((x - 1) / 2 + 1);//c1, c3, c5...的解的數量

ans += ask(discnt[(x - 1) * i + 1]) * (x / 2);//c2, c4, c6...的解的數量

isj[s[i] - 'a'] = !isj[s[i] - 'a'];

add(isj[s[i] - 'a'] ? ++jcnt : --jcnt);//最後再更新, 否則可能會導致b為空串

p *= 233;//t的長度增加, p也應該增加

} printf("%lld\n", ans);

} return 0;

}

201409 3 字串匹配

試題編號 201409 3 試題名稱 字串匹配 時間限制 1.0s 記憶體限制 256.0mb 問題描述 問題描述 給出乙個字串和多行文字,在這些文字中找到字串出現的那些行。你的程式還需支援大小寫敏感選項 當選項開啟時,表示同乙個字母的大寫和小寫看作不同的字元 當選項關閉時,表示同乙個字母的大寫和小...

20140903 字串匹配

問題描述 試題編號 201409 3 試題名稱 字串匹配 時間限制 1.0s 記憶體限制 256.0mb 問題描述 問題描述 給出乙個字串和多行文字,在這些文字中找到字串出現的那些行。你的程式還需支援大小寫敏感選項 當選項開啟時,表示同乙個字母的大寫和小寫看作不同的字元 當選項關閉時,表示同乙個字母...

201409 3 字串匹配

問題描述 給出乙個字串和多行文字,在這些文字中找到字串出現的那些行。你的程式還需支援大小寫敏感選項 當選項開啟時,表示同乙個字母的大寫和小寫看作不同的字元 當選項關閉時,表示同乙個字母的大寫和小寫看作相同的字元。輸入格式 輸入的第一行包含乙個字串s,由大小寫英文本母組成。第二行包含乙個數字,表示大小...