題面
題意
現在你有首歌,第首歌的播放時間爲,種類爲,其中,現在你從家到學校需要花費的時間,你在路上不想閒着,現在你要選幾首歌按照一定的順序播放,你要保證着幾首歌的時間總和爲(每首歌只會播放一次),並且在播放的時候不會連續播放同一種類的歌曲,計算共有多少種方案,答案對取模。
思路
狀壓,代表第中狀態最後播放的一首歌爲種類的方案數,那麼狀態轉移就有:
。
處理完所有狀態的方案數之後,再利用二進制枚舉,判斷該狀態是否可行,即總時間是否等於。
時間複雜度。
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;
}