CF626F Group Projects

发现直接做非常困难,考虑将能力值排序然后从小到大插入。

(f_{i,j,l}) 表示前 (i) 个人,有 (j) 组需要继续加人,不和谐度之和至少(l) 的方案数。此时加入一个人产生的贡献为 (t=j imes(a_{i+1}-a_i))。分三种情况转移:

  • 组数加一,即第 (i+1) 个人在一个新的组中,然后该组还需要继续加人。

    [f_{i+1,j+1,l+t}gets f_{i+1,j+1,l+t}+f_{i,j,l} ]

  • 组数不变,第 (i+1) 个人在一个新的组中,然后该组不需要继续加人,或加入了一个原有的组,然后该组还需要继续加人。

    [f_{i+1,j,l+t}gets f_{i+1,j,l+t}+f_{i,j,l} imes(j+1) ]

  • 组数减一,即第 (i+1) 个人加入了一个原有的组,然后该组不需要继续加人。

    [f_{i+1,j-1,l+t}gets f_{i+1,j-1,l+t}+j imes f_{i,j,l} ]

最后的答案就是 (sumlimits_{l=0}^k f_{n,0,l})

其实这道题无论是预处理还是 DP 部分和 JOI2012 的袋鼠都十分相似,都是通过排序来确定每次产生的贡献(变化),状态都是记录遗留下来需要继续做的量。

时间复杂度 (O(n^2k))

code:

#include<bits/stdc++.h>
using namespace std;
#define N 205
#define Mod 1000000007
#define For(i,x,y)for(i=x;i<=(y);i++)
int f[N][N][1005],a[N];
int main()
{
	int n,k,i,j,l,ans=0,t;
	cin>>n>>k;
	For(i,1,n)cin>>a[i];
	sort(a+1,a+n+1);
	f[0][0][0]=1;
	For(i,0,n-1)
	For(j,0,i)
	For(l,0,k)
	{
		t=l+j*(a[i+1]-a[i]);
		if(t<=k)
		{
			f[i+1][j+1][t]=(f[i+1][j+1][t]+f[i][j][l])%Mod;
			//作为一组的开头 
			f[i+1][j][t]=(f[i+1][j][t]+1LL*f[i][j][l]*(j+1))%Mod;
			//单独作为一组或接到一组后面 
			if(j)f[i+1][j-1][t]=(f[i+1][j-1][t]+1LL*j*f[i][j][l])%Mod;
			//作为一组的末尾 
		}
		else break;
	}
	For(l,0,k)ans=(ans+f[n][0][l])%Mod;
	cout<<ans;
	return 0;
}
原文地址:https://www.cnblogs.com/May-2nd/p/13364958.html