LG T43830 Chino的成绩

题目背景

此题为汕头某中学dalao提供

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

原出题人@月见之兔

曾经幻想过未来的风景

或许有着另外一片天

小镇的远方

有着深远的回忆

也有着富有深情的诗篇

题目描述

Chino非常注重自己的成绩

Chino有 $m$ 种方式给自己增加 $rp$ 以增加成绩,她的每种增加 $rp$ 的方式都有 $n$ 个阶段,第 $i$ 种的第 $j$ 个阶段增加的 $rp$ 表示为 $A_{ij}$ ,表示连续进行了 $j$ 天第 $i$ 种增加 $rp$ 的方式

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

输入输出格式

输入格式:

第一行,两个正整数 $n$ , $m$

接下来 $m$ 行,第 $i+1$ 行为 $n$ 个整数( $A_{i1} - A_{in}$ )

输出格式:

一行一个数,最大的 $rp$

输入输出样例

输入样例#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 \leq 50$ , $m \leq 5000$ , $a_i \leq 1e9$

对于第二个Subtask,4组数据,保证 $n \leq 70$ , $m \leq 10000$ , $a_i \leq 1e9$

对于第三个Subtask,4组数据,保证 $n \leq 100$ , $m \leq 5000$ , $a_i \leq 1e9$

其中每组数据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 ) O(n^2m^2) O(n2m2)的做法,肯定过不了就没打。以为直接背包可以骗一点分,但是并没有。。。
心态就很爆炸,赛后看了题解才会做这道题
我的dp还是弱啊。。。


先是读进来的时候顺便做前缀和,方便一会dp
然后怎么做dp
状态的参数有两个,用 f i , j f_{i,j} fi,j表示第i天做的是第j个方案的最大收益
那么 f i , j = max ⁡ ( f i − t , k + a j , t ) f_{i,j}=\max(f_{i-t,k}+a_{j,t}) fi,j=max(fit,k+aj,t) k ! = j , t < = i k!=j,t<=i k!=j,t<=i
那就可以枚举 i , j , t , k i,j,t,k i,j,t,k,但是这样的复杂度是 O ( n 2 m 2 ) O(n^2m^2) O(n2m2)
但是注意到,我们只会用到 f i − t , k f_{i-t,k} fit,k中的最大值或次大值
那么我们只需要在递推的时候记录一下即可,无需枚举k,也就是说这里可以贪心
t是要枚举的,这里并不能贪心,因为取 f i − t , k f_{i-t,k} fit,k的最大值和取 a j , t a_{j,t} aj,t的最大值都不能保证最优,两者的最大值又不一定能同时取到
这样的复杂度就是 O ( n 2 m ) O(n^2m) O(n2m)的了,这题可以过
那么我们就记录对于每一个 i , i ∈ [ 1 , n ] i,i∈[1,n] 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值