2016ACM/ICPC亞洲區大連站-重現賽 B
題目如下
給你一個長度為 n 的字串,之後 n 行每行輸入 a 然後輸入 a 個 ai 代表 字串的第 i 位可以為 a0-----aa。
最後輸入主串,問主串中包含了多少個可行的字串,輸出字串。
字串判斷題。。開始想用 kmp 但是發現 沒有重複性的話就會超時。。
所以這道題用了一個 bitset 來優化一種 shift_and 演算法。。
首先我們瞭解一下 bitset 這種東西你可以理解成一個空間優化過的 bool 陣列來表示一個數字的二進位制數。
以下為 bitset 學習部落格:https://www.cnblogs.com/RabbitHu/p/bitset.html
那麼問題來了。。這道題可以採用一種空間壓縮的思想。
第 i 位的數字可以為 j ,那麼我們不妨開 10個 bitset 來記錄數字 0-9可以出現的位置
然後再開一個 ans 作為模板串,每次 對這個模板串的末位 賦值 1 然後判斷完後就左移1位。
比如 第一位我判斷完成了, 成功匹配了 那麼這個 1移動到了第二位,我們再去判斷時(判斷我們採取 ans & num [ i ] 來處理)
如果第二位還可以出現,那麼這個 1 還會繼續向左移動下去,知道判斷到 第 n 位,如果還可以成立,那麼我們就可以知道這個
字串是符合的。。當然這麼說可能有一些抽象
舉個例子 假設 字串只有 3 為 只允許字串為 123
那麼對於 Bitset 來講
num[1] = 001 num[2] = 010 num[3] = 100
主串 為 : 122212321323
我們去模擬這個演算法做一下。。就會更加深理解。。。
看來還是太弱了。。。還需要掌握更多的演算法。。。這次終於瞭解了 bitset 是什麼。。也瞭解了一下 shift_and 演算法。。有一些收穫吧。
以下為 AC 程式碼
#include<iostream> #include<cstdio> #include<cstring> #include<bitset> using namespace std; int n; const int maxn = 5e6+5; bitset<1005> num[12]; bitset<1005> ans; char s[maxn]; int main() { while(~scanf("%d",&n)) { for(int i=0;i<10;i++) num[i].reset(); for(int i=0;i<n;i++) { int t; scanf("%d",&t); while(t--) { int k; scanf("%d",&k); num[k].set(i); } } scanf("%s",s); ans.reset(); int len=strlen(s); for(int i=0;i<len;i++) { ans = ans<<1; ans.set(0); ans=ans&num[s[i]-'0']; if(ans[n-1]) { char c=s[i+1]; s[i+1]='\0'; puts(s+i-n+1); s[i+1]=c; } } } return 0; }