【CF 1185G1】Playlist for Polycarp (easy version)(狀壓DP)

題面

題意

現在你有nn首歌,第ii首歌的播放時間爲tit_i,種類爲fif_i,其中1fi31 \leq f_i \leq 3,現在你從家到學校需要花費TT的時間,你在路上不想閒着,現在你要選幾首歌按照一定的順序播放,你要保證着幾首歌的時間總和爲TT(每首歌只會播放一次),並且在播放的時候不會連續播放同一種類的歌曲,計算共有多少種方案,答案對109+710^9+7取模。

思路

狀壓dpdp,dpi,jdp_{i,j}代表第ii中狀態最後播放的一首歌爲種類jj的方案數,那麼狀態轉移就有:
dpi(1<<k),t(t!=j)=dpi(1<<k),t(t!=j)+dpi,jdp_{i(1<<k),t(t!=j)}=dp_{i(1<<k),t(t!=j)}+dp_{i,j}
處理完所有狀態的方案數之後,再利用二進制枚舉,判斷該狀態是否可行,即總時間是否等於TT
時間複雜度n(2n)n*(2^n)

code

 #include<bits/stdc++.h>

using namespace std;
long long dp[(1<<17)+20][4];//第i個狀態最後一個爲顏色j的方案數 
const int mod = 1e9+7;
int cal(int n){
		int ans=0;
		while(n){
			ans+=(n&1);
			n>>=1;
		}
		return ans;
}
int main(){
	int a[20],b[20];
	int n,T;
	cin>>n>>T;
	for(int i=0;i<n;i++){
		 cin>>a[i]>>b[i];
	}
	for(int i=0;i<(1<<n);i++){
		if(cal(i)==1){
			for(int j=0;j<n;j++){
				if(i&(1<<j)){
					dp[i][b[j]]=1;
				}
			}
		}
	}
	for(int i=0;i<(1<<n);i++){
		for(int k=0;k<n;k++){
			if(!(i&(1<<k))){//下一個顏色 
				if(b[k]==1)  dp[i|(1<<k)][b[k]]=(dp[i|(1<<k)][b[k]]%mod+dp[i][2]%mod+dp[i][3]%mod)%mod;
				if(b[k]==2)  dp[i|(1<<k)][b[k]]=(dp[i|(1<<k)][b[k]]%mod+dp[i][1]%mod+dp[i][3]%mod)%mod;
				if(b[k]==3)  dp[i|(1<<k)][b[k]]=(dp[i|(1<<k)][b[k]]%mod+dp[i][1]%mod+dp[i][2]%mod)%mod;
			}
		}
	}
	long long ans=0;
	for(int i=0;i<(1<<n);i++){
		int ss=0;
		for(int j=0;j<n;j++){
			if(i&(1<<j)) ss+=a[j];
		}
		if(ss==T){
			ans=(ans%mod+dp[i][1]%mod+dp[i][2]%mod+dp[i][3]%mod)%mod;
		}
	}
	cout<<ans<<endl;
	return 0;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章