hdu 5000 Clone

本文探讨了DRD具有分身能力时,如何通过分析能力上限和和值来确定最多能有多少个克隆人共存,重点在于理解交错共存的情况和优化策略,最终通过简化思路得出关键结论。

题目链接

题意:DRD具有分身的能力,对于两个分身A和B来说,如果A的各个能力都强于B,那么B就无法生存(其实就是每个有一个n维向量,每个人相比于其他必须有一个突出大的,比如2,1  和 1 ,1 就不能共存)先给定DRD的n~2000种能力的上限值,上限值的和sum_t~2000,问最多有多少个克隆人可以共存,结果MOD 1E7;

题解:重点是考虑两个互相共存的东西,比如1,2 和 2 ,1  就比较好,还可以1,2 和2,0, 但是原来的可以加上3,0  后来的就不行,所以发现这样:第一,和相同的一定可以共存,交错的感觉。第二,和不相同的一定没必要共存,因为都可以对应一个替换。转换成为所有能力值和是多少的时候个数最多,本来是dp可以算的,但是因为要MOD 1E7,猜想是所有上限的和的一半最大,正态分布呗。。。或者这样想,能力和为一半,那么交错的可能性就大了。另外本题算个数,不能用2进制的多重背包来写。

重点:分析交错出现的情况,发现出特例,找出规律,往简单可做上猜想简化。想到凑出上限和的一半。另外有一种更快的写算多重背包情况数的方法。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(int i = a;i < b;i++)
#define REP_D(i, a, b) for(int i = a;i <= b;i++)

typedef long long ll;

using namespace std;

const int maxn = 2e3 + 100;<span style="font-family: Arial, Helvetica, sans-serif;">//代码很简单</span>
const int MOD = 1e9 + 7;
int dp[maxn], t[maxn], n;
int tot;
void zeroP(int k)//没有用。。。因为不能这样写,会有重复的,因为不是完美的2进制分割。
{
    for(int i = tot;i >= k;i--)
    {
        int j = i - k;
        dp[i] = (dp[i] + dp[j])%MOD;
    }
}
void getDp()
{
    memset(dp, 0, sizeof(dp));
    dp[0] = 1;
    REP_D(i, 1, n)//最笨的多重背包。
    {
        for(int j = tot;j >= 0;j--)
        {
            for(int k = 1;k <= t[i];k++)
            {
                if(j >= k)
                    dp[j] = (dp[j] + dp[j - k])%MOD;
            }
        }
    }
}
void solve()
{
    getDp();
    printf("%d\n", dp[tot]);
}

int main()
{
   // freopen("1Ain.txt", "r", stdin);
    //freopen("1Aout.txt", "w", stdout);
    int ncase;
    scanf("%d", &ncase);
    while(ncase--)
    {
        scanf("%d", &n);
        tot = 0;
        REP_D(i, 1, n)
        {
            scanf("%d", &t[i]);
            tot += t[i];
        }
        tot /= 2;//关键重点!!!!
        solve();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值