zoukankan      html  css  js  c++  java
  • noip模拟赛 补兵

    分析:比较难想的一道dp题.要想补兵的数量最多,最后每个小兵的血量肯定是呈一个阶梯状的:i,i+1,i+2......i+k.那么记录一下每个血量i离它最近的小兵的血量是多少,记作cur[i].那么把这个小兵砍成i就需要砍cur[i] - i次,显然一轮是不可能有这么多次的,只有前面的血量不去砍,留到i才有可能有砍这么多次.

          那么状态就设计为f[i][j]表示砍到了血量为i的小兵,还剩j次刀能继续砍的最大补兵数.这么设计状态的思路就是如果只用一个f[i]来记录状态的话,不知道能否达到这个状态,可能我把cur[i]砍到i之后,i-1就已经被砍死了,所以我要看前一个i-1能留多少刀给i去砍,对于i,可以将cur[i]的小兵砍成i,也可以不砍,如果不砍,那么f[i][j] = f[i-1][j-1],因为没砍,所以多了一次操作次数.如果砍的话,f[i][j] = max{f[i][j],f[i-1][j + cur[i] - i] + 1},cur[i]这个兵的血量可以变成i了,那么这个兵就能被补了,之前留的刀数就是j+cur[i]-i.不过j是有范围限制的,j<=i,因为血量i的小兵最多i次就会被老鹿砍死,最多只有i次机会,同样的,j+cur[i]-i <= i-1,因为是i-1留下的次数嘛.大致的原理就是将所有小兵的血量尽可能地变成需要的阶梯状,每次留下来的次数就留给下一次砍.

          挺难想到的.还是有一点贪心的思想,先要想出什么样的局面是最优的,再用dp来求怎么要到这样的局面.

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    int T, n, a[1010], ans, f[1010][1010], maxn,sta[1010], cur[1010], top, cnt[1010];
    
    int main()
    {
        scanf("%d", &T);
        while (T--)
        {
            memset(sta, 0, sizeof(sta));
            memset(f, 0, sizeof(f));
            top = 0;
            ans = 0;
            memset(cur, 0, sizeof(cur));
            memset(cnt, 0, sizeof(cnt));
            scanf("%d", &n);
            for (int i = 1; i <= n; i++)
            {
                scanf("%d", &a[i]);
                cnt[a[i]]++;
                maxn = max(maxn, a[i]);
            }
            for (int i = 1; i <= maxn; i++)
            {
                if (cnt[i] == 0)
                    sta[++top] = i;
                else
                {
                    while (cnt[i] > 1 && top > 0)
                    {
                        cur[sta[top--]] = i;
                        cnt[i]--;
                    }
                    cur[i] = i;
                }
            }
            for (int i = 1; i <= maxn; i++)
                for (int j = 0; j <= i; j++)
                {
                    if (j > 0)
                        f[i][j] = f[i - 1][j - 1];
                    if (cur[i] != 0 && j + cur[i] - i <= i - 1)
                        f[i][j] = max(f[i][j], f[i - 1][j + cur[i] - i] + 1);
                    ans = max(ans, f[i][j]);
                }
            printf("%d
    ", ans);
        }
    
        return 0;
    }
  • 相关阅读:
    文件管理系统(JQuery插件+Ajax)
    十大Ajax框架
    WSS3.0开发你还在为写CAML痛苦吗?
    vue获取微博授权的URL
    微博三方登录原理
    阿里云短信服务
    JWT原理和COOKIE原理
    django数据库的ORM操作
    celery原理与组件
    生成微博授权URL
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7772176.html
Copyright © 2011-2022 走看看