码迷,mamicode.com
首页 > 其他好文 > 详细

[Codeforces 626F]Group Projects

时间:2018-07-22 00:33:56      阅读:130      评论:0      收藏:0      [点我收藏+]

标签:++   时空   i+1   const   codeforce   sync   pre   题目   [1]   

 

题目大意:

给定\(n\)个数\(a[1]\sim a[n]\),让你把它分为若干个集合,使每个集合内最大值与最小值的差的总和不超过\(K\)。问总方案数。

解题思路:

一道很神的dp题。

首先将数进行排序,然后将这些数扔数轴上,则集合价值相当于在数轴上覆盖这些点所用的最短线段的长度(当然长度可以为0)。

考虑dp,设\(f[i][j][k]\)表示考虑了前\(i\)个点,目前还未确定右端点的集合还有\(j\)条,目前的总价值为\(k\),则

不论如何,新加进\(a[i+1]-a[i]\)这条线段,对\(j\)个集合均有影响,因此会增加价值为\((a[i+1]-a[i])\times j\),设其为\(t\)。

转移分四种情况:

1. 该点单独成一个集合,则\(j\)不变,仅有1种情况,\(f[i+1][j][k+t]+=f[i][j][k]\);
2. 该点作为某个集合的中间元素,则\(j\)也不变,对于\(j\)个集合都有可能,因此\(f[i+1][j][k+t]+=f[i][j][k]\times j\);
3. 该点作为一个集合的起点,则集合数多了1,仅有1种情况,\(f[i+1][j+1][k+t]+=f[i][j][k]\);
4. 该点作为一个集合的终点,则集合数少了1,对于\(j\)个集合都有可能,因此\(f[i+1][j−1][k+t]+=f[i][j][k]\times j\)。

答案为\(\sum\limits_{i=0}^K f[n][0][i]\)。

时空复杂度均为\(O(n^2K)\),空间复杂度可以用滚动数组优化到\(O(nK)\)。

C++ Code:

#include<bits/stdc++.h>
using namespace std;
const int md=1e9+7;
int n,K,cur,a[201],dp[2][201][1001];
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>K;
	for(int i=1;i<=n;++i)cin>>a[i];
	sort(a+1,a+n+1);
	dp[1][1][0]=dp[1][0][0]=cur=1;
	for(int i=1;i<n;++i){
		const int otr=cur;
		memset(dp[cur^=1],0,sizeof dp[0]);
		for(int j=0;j<=i;++j){
			const int t=j*(a[i+1]-a[i]);
			for(int k=0;k+t<=K;++k){
				dp[cur][j][k+t]=(dp[cur][j][k+t]+dp[otr][j][k]*(j+1ll)%md)%md;
				if(j<n)dp[cur][j+1][k+t]=(dp[cur][j+1][k+t]+dp[otr][j][k])%md;
				if(j)dp[cur][j-1][k+t]=(dp[cur][j-1][k+t]+1ll*dp[otr][j][k]*j%md)%md;
			}
		}
	}
	int ans=0;
	for(int i=0;i<=K;++i)
	ans=(1ll*dp[cur][0][i]+ans)%md;
	cout<<ans<<endl;
	return 0;
}

 

[Codeforces 626F]Group Projects

标签:++   时空   i+1   const   codeforce   sync   pre   题目   [1]   

原文地址:https://www.cnblogs.com/Mrsrz/p/9348255.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!