您的位置:首页 > 其它

codeforces 626F DP 如何设置状态,方便转移

2016-03-05 11:32 225 查看
想到用动态规划来做,但是考虑到第i个数的时候,前面数的分组情况并不知道,开始准备用类似并查集的方法,但是也不好保存

能够利用的性质是只和最大最小有关,所以想到排序之后解决,但是还是不知道应该怎么扩展状态。

看了题解,DP[I][J][K]表示考虑到第i个的时候,总共还有j组没有关闭,所需的费用,每次扩展状态的时候给所有的j加上a[i] - a[i-1] 这样以后结束的时候,加上去就可以了,只要考虑有多少组要加上这个,就可以得到答案,还有一点需要注意的是,第i个可以一个人构成一个闭组,或者一个人构成一个开组,或者和前面的组成闭组,或者和前面的组成开组,和前面的组的时候,记得乘以可能的组数,因为并到任何一组都是不同的,真是好题……想不到啊

上搞了半天才AC而且时间有点长,有点丑的代码

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 205;
const int maxk = 1000;
const int M = 1000000007;
int n,k;
int a[maxn];
int dp[maxn][maxn + 1][maxk + 1];
int main()
{
cin >> n >> k;
for(int i = 0; i < n; i++)
cin >> a[i];
sort(a,a + n);
memset(dp,0,sizeof(dp));
dp[0][0][0] = 1;
dp[0][1][0] = 1;
for(int i = 1; i < n; i++)
for(int j = 0; j <= i + 1; j++)
for(int p = 0; p <= k; p++){
int t;
if ((t = p - (a[i] - a[i - 1]) * j) >= 0 )
dp[i][j][p] += dp[i - 1][j][t];//单独一个,闭了,对前面j个没闭的有影响
if (j >= 1 && (t = p - (a[i] - a[i - 1]) * (j- 1)) >= 0) dp[i][j][p] = (dp[i][j][p] + dp[i - 1][j - 1][t]) % M;//单独一个,不闭 ,对前面J - 1个没闭的有影响
if ((a[i] - a[i - 1]) * (j + 1) <= p && j + 1 <= n) //和前面的某个闭
dp[i][j][p] = (dp[i][j][p] + (long long) (j + 1) * dp[i - 1][j + 1][p - (a[i] - a[i - 1])*(j + 1)] % M) %M;;
if ((a[i] - a[i - 1]) * j <= p && j != 0)//和前面某个在一起,不闭
dp[i][j][p] = (dp[i][j][p] + (long long )j * dp[i - 1][j][p - (a[i] - a[i - 1])*j] % M) % M;
//printf("%d %d %d %d\n",i,j,p,dp[i][j][p]);
}
int ans = 0;
for(int p = 0; p <= k; p++)
ans = (ans + dp[n - 1][0][p]) %M;
cout << ans << '\n';
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息