LG T43830 Chino的成绩

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/suxuyu01/article/details/82081400

题目背景

此题为汕头某中学dalao提供

由其学校内部赛原题改编,并非原题且并未公开

原出题人@月见之兔

曾经幻想过未来的风景

或许有着另外一片天

小镇的远方

有着深远的回忆

也有着富有深情的诗篇

题目描述

Chino非常注重自己的成绩

Chino有 m 种方式给自己增加 r p 以增加成绩,她的每种增加 r p 的方式都有 n 个阶段,第 i 种的第 j 个阶段增加的 r p 表示为 A i j ,表示连续进行了 j 天第 i 种增加 r p 的方式

Chino连续进行同一种方式,效果可能更好也可能更差,她想要知道在 n 天里能获得的最大 r p ,你能帮帮可爱的Chino吗?

输入输出格式

输入格式:

第一行,两个正整数 n m

接下来 m 行,第 i + 1 行为 n 个整数( A i 1 A i n )

输出格式:

一行一个数,最大的 r p

输入输出样例

输入样例#1: 复制
3 3
3 2 1
3 1 1
3 3 1
输出样例#1: 复制
9

输入样例#2: 复制
3 3
3 2 1
3 5 2
4 1 1
输出样例#2: 复制
12

说明

本题分为3个Subtask

第一个Subtask,2组数据 ,保证 n 50 m 5000 a i 1 e 9

对于第二个Subtask,4组数据,保证 n 70 m 10000 a i 1 e 9

对于第三个Subtask,4组数据,保证 n 100 m 5000 a i 1 e 9

其中每组数据4分,对于每个Subtask及其中的每个数据点,取分数和。

样例解释1

1 天进行第 1 项活动,获得 A 11 = 3 点rp。

2 天进行第 2 项活动,获得 A 21 = 3 点rp。

3 天进行第 1 项活动,获得 A 11 = 3 点rp。

样例解释2

1 天进行第 2 项活动,获得 A 21 = 3 点rp。

2 天进行第 2 项活动,获得 A 22 = 5 点rp(因为已经连续进行了 2 次第 2 项活动,因而是 A 22 而不是 A 21

3 天进行第 3 项活动,获得 A 31 = 4 点rp。



看到题目基本上可以确定这题是道dp题,但是怎么dp我没有想出来
一开始当背包做的,想出来 O ( n 2 m 2 ) 的做法,肯定过不了就没打。以为直接背包可以骗一点分,但是并没有。。。
心态就很爆炸,赛后看了题解才会做这道题
我的dp还是弱啊。。。


先是读进来的时候顺便做前缀和,方便一会dp
然后怎么做dp
状态的参数有两个,用 f i , j 表示第i天做的是第j个方案的最大收益
那么 f i , j = max ( f i t , k + a j , t ) k ! = j , t <= i
那就可以枚举 i , j , t , k ,但是这样的复杂度是 O ( n 2 m 2 )
但是注意到,我们只会用到 f i t , k 中的最大值或次大值
那么我们只需要在递推的时候记录一下即可,无需枚举k,也就是说这里可以贪心
t是要枚举的,这里并不能贪心,因为取 f i t , k 的最大值和取 a j , t 的最大值都不能保证最优,两者的最大值又不一定能同时取到
这样的复杂度就是 O ( n 2 m ) 的了,这题可以过
那么我们就记录对于每一个 i , i [ 1 , n ] 的最大值b[i]和次大值sb[i]以及它取到最大值时的方案编号bi[i]
然后就还有一些代码细节问题了,比如题解的代码的每个i的最大和次大的处理就比较厉害,如果当前值>扫过的当前的最大值,交换当前值与扫过的当前的最大值,然后再把当前值与次大值比较,可能说比较不太清晰,看代码就会比较清晰


代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define For(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
inline int read()
{
    char c;
    bool t=0;
    int a=0;
    while((c=getchar())==' '||c=='\n'||c=='\r');
    if(c=='-')
    {
        t=1;
        c=getchar();
    }
    while(isdigit(c))
    {
        a*=10;
        a+=(c-'0');
        c=getchar();
    }
    return a*(t?-1:1);
}
int n,m,a[10010][101],b[110],bi[110],sb[110];
inline int get(int i,int j)
{
    return bi[i]==j?sb[i]:b[i]; 
}
int main()
{
    int temp;
    n=read();m=read();
    For(i,1,m)
     For(j,1,n)
     { 
        a[i][j]=read();
        a[i][j]+=a[i][j-1];
     }
    For(i,1,n)
     For(j,1,m)
     {
        temp=0;
        For(k,1,i)
         temp=max(temp,get(i-k,j)+a[j][k]);
        if(temp>b[i])
        {
            swap(temp,b[i]);
            bi[i]=j;
        }
        if(temp>sb[i])
         sb[i]=temp;
     }
    printf("%d",b[n]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/suxuyu01/article/details/82081400