2020“远光杯”网络资格赛L 捕鱼达人(树状数组/区间最大值/单点更新)

题目

门前大桥下,游过一群鱼,小红鱼,黄花鱼,绿草鱼,蓝顶鱼,粉鲳鱼,砂紫鱼,竟然在鱼塘中排成了一条队列,捕鱼达人坤坤打算将他们捕获。但是由于这些鱼比较稀有,坤坤需要在指定的规则下才能抓捕他们,规则如下:

  1. 在捕鱼过程中当前捕获的鱼颜值必须大于等于前一条鱼颜值a_i,对于捕获的第一条鱼没有要求。

  2. 每一条鱼变身后他的价值b_i为他的颜值的1/10000(整除)。

  3. 每一条鱼变身后他的颜值会变成原本颜值对10000的余数,也就是a_i%10000。(例如变身前颜值a_i为20001,则变身后它的价值变为2,颜值变为1)。

  4. 所有鱼在一开始的时候就会变身,变身后坤坤才可以开始捕鱼。

  5. 鱼群顺序是从左到右排列的,鱼群的顺序是不可变的,坤坤可以从鱼群头或者鱼群尾开始捕鱼,但是顺序必须是从左到右或者从右到左。

  6. 坤坤希望他捕获到的鱼的价值最多。

输入要求
第一行先输入一个T(1 <= T <= 10)表示接下去有T组数据

对于每组数据

第一行会有一个n(1 <= n <= 10^4)表示接下来从左到右会有n条鱼。

第二行会有n个数,对于每个数表示这个鱼的颜值为a_i(-6 * 10^4 < a_i < 6 * 10^4)。

输出要求
对于每组数据,输出Case #i: val

表示当前为第i组数据,每次捕鱼获得的最大价值为val。

对于每行输出,最后没有空格,输出后直接换行。
样例输入

5  
5  
10001 10002 10003 10004 10001  
5  
50001 10001 10002 10003 10004  
5  
50001 10002 10003 10004 10005  
5  
50005 10001 10002 10003 10004  
5  
-10001 -10002 -10003 -10004 0  

样例输出

Case #1: 4
Case #2: 9
Case #3: 9
Case #4: 6
Case #5: 0

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
const int maxn = 10010;
const int maxm = 20010;

int dp[maxm],n;
int a[maxn];//颜值 
int b[maxn];

int h[maxm];
int lowbit(int x) {
	return x&(-x);
} 
void update(int x) {//单点更新 
	while(x < maxm) {
		h[x] = dp[x];
		for(int i = 1;i < lowbit(x);i <<= 1)
			h[x] = max(h[x],h[x-i]);
		x += lowbit(x);
	}
	return;
}
int query(int st,int ed) {//查询区间最大值 
	int ans = 0;
	while(ed >= st) {
		ans = max(ans,dp[ed]);
		--ed;
		for(;ed-lowbit(ed) >= st;ed -= lowbit(ed)) {
			ans = max(ans,h[ed]);
		}
	}
	return ans;
}
int main() {
	int t,cas = 1;scanf("%d",&t);
	while(t--) {
		scanf("%d",&n);
		for(int i = 1,x;i <= n;++i) {
			scanf("%d",&x);
			a[i] = x%10000+10000;
			b[i] = x/10000;
		} 
		for(int i = 0;i < maxm;++i) dp[i] = h[i] = 0;
		int ans = 0;
		for(int i = 1;i <= n;++i) {
			int val = a[i];
//			for(int j = 0;j < a[i];++j) {
//				dp[val] = max(dp[val],dp[j]);
//			}
			if(a[i] > 0)
				dp[val] = query(1,a[i]);
			if(b[i] > 0) {
				dp[val] += b[i];
				update(val);
			}
			ans = max(ans,dp[val]);
		}
		for(int i = 0;i < maxm;++i) dp[i] = h[i] = 0;
		for(int i = n;i >= 1;--i) {
			int val = a[i];
//			for(int j = 0;j < a[i];++j) {
//				dp[val] = max(dp[val],dp[j]);
//			}
			if(a[i] > 0)
				dp[val] = query(1,a[i]);
			if(b[i] > 0) {
				dp[val] += b[i];
				update(val);
			}
			ans = max(ans,dp[val]);
		}
		printf("Case #%d: %d\n",cas++,ans);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值