1. 程式人生 > >2016ACM/ICPC亞洲區大連站-重現賽 B

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;
}