首页 > 代码库 > HDU 5000 Clone

HDU 5000 Clone

题意:

每个克隆个体有n个属性  如果对于A、B两个个体  A的n个属性均不低于B的n个属性  那么B会被淘汰  问最多能有多少个体同时存活

思路:

根据数据大小猜一下是n^2的复杂度  往DP方面考虑一下

DP需要一个想法的支持  就是最优的那个集合中的元素的n个属性的和一定是一样的  为什么呢?  想象一下  假设最优的集合的属性和是5  这时你选过来一个和为6或者4的元素  那么至少会造成2个和为5的解从集合中被扔掉  选进1个扔掉2个明显是不合适的  而且这个最优的属性和必然为n个属性最大值的和的一半

假设每个属性的最大值为ti  那么sumt/2就是最优的属性和  那么问题就变成了  取n个数字  第i个数字在0到ti之间  问和为sumt/2的方案有几种  这就可以DP了

dp[i][j]表示第i个数字和为j的方案数  那么转移就是dp[i][j]=dp[i-1][j-ti]+dp[i-1][j-ti+1]+...+dp[i-1][j]  我们发现如果只用for需要3个循环  但是这是一个连续求和式子  用树状数组优化  就可以O(n^2logn)解决了

PS:这题杭电卡的时间比较死  不要每次循环都做到2000  因为sumt/2以后的数字全没用  所以别算

代码:

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<vector>
#include<cassert>
using namespace std;
typedef long long LL;
#define Q 401
#define N 2002
#define M 200001
#define inf 2147483647
#define mod 1000000007
#define lowbit(x) (x&(-x))

int t, n, p;
int d[N];
LL f[N][N];

void add(int r, int x, int v) {
	for (; x <= p; x += lowbit(x)) {
		f[r][x] += v;
		if (f[r][x] > mod)
			f[r][x] -= mod;
	}
}

LL sum(int r, int x) {
	LL res = 0;
	for (; x > 0; x -= lowbit(x))
		res += f[r][x];
	return res % mod;
}

int main() {
	int i, j, k, tmp;
	scanf("%d", &t);
	while (t--) {
		memset(f, 0, sizeof(f));
		p = 0;
		scanf("%d", &n);
		for (i = 1; i <= n; i++) {
			scanf("%d", &d[i]);
			p += d[i];
		}
		p = p / 2 + 1;
		for (i = 1; i <= d[1] + 1; i++)
			add(1, i, 1);
		for (i = 2; i <= n; i++) {
			for (j = 1; j <= p; j++) {
				k = j - d[i] - 1;
				tmp = (sum(i - 1, j) - sum(i - 1, k) + mod) % mod;
				add(i, j, tmp);
			}
		}
		printf("%lld\n", (sum(n, p) - sum(n, p - 1) + mod) % mod);
	}
	return 0;
}


HDU 5000 Clone