题目链接:https://codeforces.com/contest/1185/problem/G1
题意:
给你n首歌的长度以及歌曲类型,现在问你有多少种歌曲的组合使得,组合中歌曲总时长为已知T,且组合中每首歌最多只出现一次,没有出现同一类型的歌曲连续的情况。
做法:
因为n最多为15,类型不超过三种,歌曲长度最多为15,且T最多为225,所以挺明显是状压dp的,状态也比较好想,dp[i][j]代表状态为i(即15首歌中听过为1,没听过为0)情况下,听过的最后一首歌类型为j的情况(因为要控制同一类型的歌不会连续出现),状态转移方程为,当前for到的状态是i,歌曲是j,如果i中有j,那么就从没有j的状态转移过来,同时要求g[j]和k不同。
脑子大概是不好使了,什么时候把答案进行增加一下子都没反应过来。
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=(1<<15);
int n,T;
int t[20],g[20];
ll dp[maxn+5][3],sti[maxn+5];
int main(){
scanf("%d%d",&n,&T);
rep(i,0,n-1){
scanf("%d%d",&t[i],&g[i]);
g[i]--;
}
ll ans=0;
for(int i=1;i<maxn;i++){
for(int j=0;j<n;j++){
if((i&(1<<j))==0) continue;
sti[i]=sti[i-(1<<j)]+t[j];
if(i==(1<<j)) dp[i][g[j]]=1;
else {
for(int k=0;k<3;k++){
if(k==g[j]) continue;
dp[i][g[j]]=(dp[i][g[j]]+dp[i-(1<<j)][k])%mod;
}
}
}
if(sti[i]==T){
rep(k,0,2){
ans=(ans+dp[i][k])%mod;
}
}
}
printf("%lld\n",ans);
return 0;
}