[BZOJ 1879][SDOI 2009]Bill的挑战 题解(状压DP)
[BZOJ 1879][SDOI 2009]Bill的挑戰(zhàn)
Description
Solution
1.考慮狀壓的方式。
方案1:如果我們把每一個字符串壓起來,用一個布爾數(shù)組表示與每一個字母的匹配關系,那么空間為26^50,爆內(nèi)存;
方案2:把每一個串壓起來,多開一維記錄匹配字符,那么空間為nlen26,合法,但不便于狀態(tài)的設計和轉(zhuǎn)移;
方案3:把每一個串同一個位置的字符放在一起,用一個布爾數(shù)組記錄與每一個小寫字母的匹配關系,那么空間為26^15*len,爆內(nèi)存;
方案4:把每一個串同一個位置的字符壓起來,用多開一維的整形數(shù)組記錄與每一個小寫字母的匹配關系,空間為2^15*len,合法;
采用方案4,那么關系具體的記錄方式就是,開一個壓縮數(shù)組r[2^15][len],r[i][j]表示所有串第i位與第j個小寫字母的匹配情況:
例如,第1到n個串的第i位分別為:?,a, b,c,那么他們與'a'的匹配情況為r[i][0]=0011;
void init(){for(R int i=0;i<len;++i)//第i列 for(R int x=0;x<26;++x){//對'a'增量為x r[i][x]=0;for(R int k=0;k<n;++k)//第k個串 if(s[k][i]=='?'||s[k][i]=='a'+x)r[i][x]|=(1<<k);} }2.考慮DP的過程
方案1:f[i][j]表示當前匹配長度位i,狀態(tài)為j,實際上也就是符合要求的匹配情況為j時的方案數(shù)
方案2:f[i][j]表示當前匹配到第i位,狀態(tài)為j時的方案數(shù);
兩種方案均可,只是第一種的i永遠比第二種的i多1罷了。
但是我們要采用方案1,因為初始化時,未匹配情況應該只有一個那就是111...111,所以對于第一種情況初始化就非常簡單,也就是f[0][(1<<n)-1]=1;
然后就是轉(zhuǎn)移,我們發(fā)現(xiàn)當且僅當前一位時當前狀態(tài)合法才可轉(zhuǎn)移,我們轉(zhuǎn)移采用擴展狀態(tài)的方式,即在當前狀態(tài)上枚舉增加狀態(tài),所以狀態(tài)轉(zhuǎn)移方程是:
(f[i][j&r[i-1][x]]+=f[i-1][j])%=mod;
Code
#include<iostream> #include<cmath> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define R register typedef long long ll; using namespace std;const int mod=1e6+3;string s[20]; int n,m,r[51][50010],f[51][50010];inline int lowbit(int x){return x&-x;}void init(){cin>>n>>m;memset(f,0,sizeof(f));for(R int i=0;i<n;++i)cin>>s[i];int len=s[0].size();for(R int i=0;i<len;++i)//第i列 for(R int x=0;x<26;++x){//對'a'增量為x r[i][x]=0;for(R int k=0;k<n;++k)//第k個串 if(s[k][i]=='?'||s[k][i]=='a'+x)r[i][x]|=(1<<k);} }void work(){int lim=(1<<n)-1;int len=s[0].size();f[0][lim]=1;for(R int i=1;i<=len;++i)for(R int j=0;j<=lim;++j)//狀態(tài) if(f[i-1][j])//如果當前前一列子集被更新過,即要擴展的狀態(tài)合法 for(R int x=0;x<26;++x)//對'a'增量為x(f[i][j&r[i-1][x]]+=f[i-1][j])%=mod; int ans=0;for(R int i=0;i<=lim;++i){int temp=i,cnt=0;while(temp){cnt++;temp-=lowbit(temp);}if(cnt==m) (ans+=f[len][i])%=mod;}printf("%d\n",ans); } int main(){ios::sync_with_stdio(false);int t;cin>>t;while(t--){init();work();}return 0; }轉(zhuǎn)載于:https://www.cnblogs.com/COLIN-LIGHTNING/p/9062662.html
總結(jié)
以上是生活随笔為你收集整理的[BZOJ 1879][SDOI 2009]Bill的挑战 题解(状压DP)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 项目文件中的已知 NuGet 属性(使用
- 下一篇: Docker常用操作命令