https://codeforces.com/contest/1185/problem/G1
G2做不来;
题意:给你一个时间T和n首歌,每一首歌都有它的时间和类型,要求每一首歌只能安排一次,并且同类型不能安排在一起,问吧时间T放满一共有多少种方法。
做法:由于范围比较小可以直接用一个状态压缩来表示状态,设dp[i][j][k]表示i时间状态j结尾是k类型的歌的种类,其中j是一个压缩状态,于是可以遍历歌曲总数k ,就有如下式子。
if((i&(1<<(k-1)))==0)
dp[j+a[k]][s][b[k]]=dp[j+a[k]][s][b[k]]+dp[j][i][m];
这道题就可以AC了
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
const int M=20;
typedef long long ll;
const ll mod=1e9+7;
const int inf=0x3f3f3f3f;
int n,T;
int a[N],b[N];
ll dp[230][(1<<15)+10][3];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>T;
for(int i=1;i<=n;i++)
{
cin>>a[i]>>b[i];
b[i]--;
}
for(int i=1;i<=n;i++)
{
dp[a[i]][1<<(i-1)][b[i]]=1;
}
for(int j=1;j<=T;j++)
{
for(int i=1;i<(1<<n);i++)
{
for(int m=0;m<3;m++)
{
if(dp[j][i][m])
for(int k=1;k<=15;k++)
{
if(j+a[k]>T) continue;
if((i&(1<<(k-1)))!=0) continue;
if(m==b[k]) continue;
int s=i^(1<<(k-1));
dp[j+a[k]][s][b[k]]=(dp[j+a[k]][s][b[k]]+dp[j][i][m])%mod;
}
}
}
}
ll ans=0;
for(int j=1;j<(1<<n);j++)
for(int i=0;i<=2;i++)
ans=(ans+dp[T][j][i])%mod;
cout<<ans<<endl;
return 0;
}