zoukankan      html  css  js  c++  java
  • 牛客多校第六场 J Upgrading Technology dp

    题意:

    有n个技能,一开始都是0级,第i个技能从j-1级升到j级,花费$c_{i,j}$,但是花费不一定是正的

    所有的技能升到j级时,奖励$d_j$但是奖励也不一定是正的

    题解:

    用sum[i][j]储存-c[i][j]的前缀和,即技能i升到j级后总共的收益

    再用w[j]储存f[j]的前缀和,代表所有的技能都升到j的收益。

    再开一个数组maxxx[i][j]用于储存技能i至少升到j级的收益,即max(sum[i][j~m])。

    然后枚举j,计算$w_j+sum_{i=1}^{n}maxxx[i][j]$即可

    但这样带来一个问题,对于某个j,假如每种技能在最少升到j级的情况下,最优情况都是需要升到更高级,那么,所有的技能都升级带来的奖励d你就必须收下,即便这个d是负的。

    因此,定义bonus=maxxx[i][j]-sum[i][j],代表某个技能因为升到高于j得到的额外奖励,当对于某个j,所有的技能带来的bonus都大于0,就减去那个最小的bonus,表示以最小的代价把一个技能打回j级,这样就保证了计算出来的奖励d是正确的。

    #include<iostream>
    #include<cstring>
    #define LL long long
    #define INF 0x3f3f3f3f3f3f3f3f
    using namespace std;
    LL sum[1005][1005];
    LL maxxx[1005][1005];
    LL d[1005];
    
    int main(){
    //    int i;
    //    int j; 
        int t;
        scanf("%d",&t);
    //    for(int i=0;i<=1000;i++){
    //        for(int j=0;j<=1000;j++){
    //            printf("%lld ",sum[i][j]);
    //        }
    //        printf("
    ");
    //    }
        for(int tt=1;tt<=t;tt++){
            int n,m;
            scanf("%d %d",&n,&m);
    //        memset(sum,0,sizeof sum);
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++){
                    scanf("%lld",&sum[i][j]);
                    sum[i][j]=-sum[i][j];
                    sum[i][j]+=sum[i][j-1];
                }
    //            for(int j=0;j<=m;j++)printf("%lld ",sum[i][j]);
    //            printf("
    ");
                maxxx[i][m]=sum[i][m];
                for(int j=m;j>=1;j--){
                    maxxx[i][j-1]=max(sum[i][j-1],maxxx[i][j]);
                    //最少修炼到第j层时最大收益 
                }
    //            for(int j=0;j<=m;j++)printf("%lld ",maxxx[i][j]);
    //            printf("
    ");
            }
            for(int i=1;i<=m;i++){
                scanf("%lld",&d[i]);
                d[i]+=d[i-1];
            }
            LL maxx=0;
            for(int j=0;j<=m;j++){
                //最少修炼到第j层
                LL now=d[j];
                int bonustimes=0;
                LL minbonus=INF;
                for(int i=1;i<=n;i++){
                    now+=maxxx[i][j];
                    if(maxxx[i][j]>sum[i][j]){
                        bonustimes++;
                        minbonus=min(minbonus,maxxx[i][j]-sum[i][j]);
                    }
                }
    //            printf("bun:%lld
    ",minbonus);
                if(bonustimes==n)now-=minbonus;
                maxx=max(maxx,now); 
            }
            printf("Case #%d: %lld
    ",tt,maxx); 
        }
        return 0;
    }

    PS:

    本题带来了一个教训,格式输入一定不要偷懒,要对于所有的数据类型都采用正确的格式符号,即便题目限定了输入范围。

    比如在做这道题时,我发现,如果你用%d输入long long,因为%d只给了变量的后32位赋值,但是注意,对于负数,因为补码运算,int 和long long不是简单的截掉头部的关系。

    比如你输入-1,32位的-1是11111111111111111111111111111111

    但是如果乱用格式符号,导致64位变量只有后32位被赋值,则变成了0000000000000000000000000000000011111111111111111111111111111111

    这个数对应的是4294967295

    浮点数乱七八糟的就更多了。

    正确的格式符号:

    scanf:%d->int %lld/%l64d->long long (视编译器而定)  %f->float %lf->double

    printf:%f->float/double

    如果忽略这点,就会导致莫名其妙的wa。

  • 相关阅读:
    图的存储结构(精编)
    二叉树的输入
    哈夫曼树及编码
    C. Bits (Codeforces Round #276 (Div. 2) )
    C++ Map 容器
    POJ 1080 Human Gene Functions(dp)
    数和二叉树——二叉树的建立及应用(遍历等)(基础篇)
    数独问题的介绍及POJ 2676-Sudoku(dfs+剪枝)
    【数据结构】——稀疏矩阵转置
    POJ 3083 Children of the Candy Corn
  • 原文地址:https://www.cnblogs.com/isakovsky/p/11296444.html
Copyright © 2011-2022 走看看