题解 CF1185G2 【Playlist for Polycarp (hard version)】

· · 题解

CF1185G2 Playlist for Polycarp

题面

英文题面

题意:有n首歌,每首歌有时间t_i,类型g_i。你需要选出若干首歌并将他们排成一排,满足相邻两首歌的类型不能相同,所有歌的时间总和为T。求方案数。

题解:我们可以考虑先将两个限制分开考虑,然后再尝试合并。 先考虑第二个限制。设$a_{i,t}$表示第一种歌用了$i$个,总时长为$t$的方案数,$b_{i,j,t}$表示第二种、第三种歌分别选了$i$,$j$个,总时长为$t$的方案数。转移时就用01背包的转移方式即可。时间复杂度是$O(n^3 \times T)$的。 再考虑第一个限制。设$f_{i,j,k,l}$表示三种歌各选了$i,j,k$次,最后一个选的是$l$的方案数。转移就每次枚举往序列最后放哪个数即可。时间复杂度是$O(n^3)$的。 最后考虑将它们合并。我们枚举$i,j,k,t$,表示三种歌各选了$i,j,k$个,其中第一种歌的总时间是$t$。那么方案数为: $$a_{i,t} \times b_{j,k,T-t} \times i! \times j! \times k! \times f_{i,j,k,0/1/2}$$ 累加一下就是答案了。 时间复杂度:$O(n^3 \times T)$,常数非常小,可以通过本题。 代码: ```c++ #include<bits/stdc++.h> using namespace std; #define re register int #define F(x,y,z) for(re x=y;x<=z;x++) #define FOR(x,y,z) for(re x=y;x>=z;x--) typedef long long ll; #define I inline void #define IN inline int #define C(x,y) memset(x,y,sizeof(x)) #define STS system("pause") template<class D>I read(D &res){ res=0;register D g=1;register char ch=getchar(); while(!isdigit(ch)){ if(ch=='-')g=-1; ch=getchar(); } while(isdigit(ch)){ res=(res<<3)+(res<<1)+(ch^48); ch=getchar(); } res*=g; } const int Mod=1e9+7,N=55,M=2550; int n,m,T,ans,fac[N],sum[3],cnt[3],t[N],s[N],a[N][M],b[N][N][M],f[N][N][N][4]; I add(int &x,int y){(x+=y)>=Mod?x-=Mod:0;} IN Plus(int x,int y){(x+=y)>=Mod?x-=Mod:0;return x;} int main(){ read(n);read(T); F(i,1,n)read(t[i]),read(s[i]),s[i]--; fac[0]=1;F(i,1,n)fac[i]=(ll)fac[i-1]*i%Mod; a[0][0]=1;b[0][0][0]=1; F(j,1,n){ cnt[s[j]]++;sum[s[j]]+=t[j]; if(s[j]==1)FOR(i,cnt[1],1)FOR(k,cnt[2],0)FOR(l,sum[1]+sum[2],t[j])add(b[i][k][l],b[i-1][k][l-t[j]]); else if(s[j]==2)FOR(i,cnt[1],0)FOR(k,cnt[2],1)FOR(l,sum[1]+sum[2],t[j])add(b[i][k][l],b[i][k-1][l-t[j]]); else FOR(i,cnt[0],1)FOR(k,sum[0],t[j])add(a[i][k],a[i-1][k-t[j]]); } if(cnt[0])f[1][0][0][0]=1;if(cnt[1])f[0][1][0][1]=1;if(cnt[2])f[0][0][1][2]=1; F(s,2,n)F(i,0,min(cnt[0],s))F(j,0,min(cnt[1],s-i)){ re k=s-i-j;if(k>cnt[2])continue; if(i)add(f[i][j][k][0],f[i-1][j][k][1]),add(f[i][j][k][0],f[i-1][j][k][2]); if(j)add(f[i][j][k][1],f[i][j-1][k][0]),add(f[i][j][k][1],f[i][j-1][k][2]); if(k)add(f[i][j][k][2],f[i][j][k-1][0]),add(f[i][j][k][2],f[i][j][k-1][1]); } F(i,0,cnt[0])F(j,0,cnt[1])F(k,0,cnt[2])f[i][j][k][3]=Plus(f[i][j][k][0],Plus(f[i][j][k][1],f[i][j][k][2])); ans=0; F(l,0,T)F(i,0,cnt[0]){ if(!a[i][l])continue; F(j,0,cnt[1])F(k,0,cnt[2])if(b[j][k][T-l])add(ans,(ll)a[i][l]*b[j][k][T-l]%Mod*fac[i]%Mod*fac[j]%Mod*fac[k]%Mod*f[i][j][k][3]%Mod); } printf("%d",ans); return 0; } ```