zoukankan      html  css  js  c++  java
  • BZOJ 3897: Power

    3897: Power

    Time Limit: 30 Sec  Memory Limit: 512 MB
    Submit: 218  Solved: 83
    [Submit][Status][Discuss]

    Description

    我们假设小T有一个人体耐力上限E,在月初的时候,小T有E的体力。
    接下来每一天有一个任务,这个任务小T可以付出任意的非负整数体力去完成,并且,每一天的结束的时候,小T会增加R的体力。当然体力是不可能超出E的,也就是说,如果当前体力+R大于E,那么恢复完之后的体力依旧是E。毫无疑问,体力是不可能小于0的。
    每个任务会有一个价值V[],一个任务的收获就是这个任务的价值乘上付出的体力。
    你要帮帮小T,使他最大化 “所有任务的收获之和”, 方便他继续的高富帅!
    最后,我们的口号是“烧死GFS~”。

    Input

    第一行一个正整数case,表示数据的组数。
    对于每一组数据,第一行有三个正整数E,R,N,表示的是能量上限,恢复值,和这个月的天数。第二行有N个非负整数表示V[1]-V[N]。

    Output

    对于一组数据,一行输出最大化的收获之和。

    Sample Input

    1
    5 2 2
    2 1

    Sample Output

    12

    HINT

    第一天用5的体力,接下来恢复2点体力,再用光。

    Can<=10,N<=500000,E<=10^6.所有的输入非负,并且,V<=10^6。

    Source

    By 佚名提供

    分析:

    考虑我们一定是让大的权值尽量被提供较多的体力,并且要求不能溢出,那么考虑分治的思想,定义$f(l,r,be,en)$为从第l天到第r天,初始体力为be结束时体力为en的最优解,我们选择这个区间中权值最大的那个点x,如果这一天前面发那些天都休养生息还不能满足使得第x天的初始体力为E,那么前面几天就歇着吧,否则就是溢出了,溢出是浪费,所以就递归到前面那几天去贡献,后面几天也是一样的...

    代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    //by NeighThorn
    using namespace std;
    
    const int maxn=500000+5;
    
    int n,E,R,cas,v[maxn],st[maxn][25];
    
    inline bool cmp(int x,int y){
    	return v[x]<v[y];
    }
    
    inline void init(void){
    	for(int i=1;i<=n;i++)
    		st[i][0]=i;
    	for(int j=1;j<=20;j++)
    		for(int i=1;i+(1<<j-1)<=n;i++)
    			st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1],cmp);
    }
    
    inline int query(int x,int y){
    	if(x>y)
    		swap(x,y);
    	int len=y-x+1,k;
    	for(k=20;k>=0;k--)
    		if(((len>>k)&1)||k==0)
    			break;
    	return max(st[x][k],st[y-(1<<k)+1][k],cmp);
    }
    
    inline long long solve(int l,int r,int be,int en){
    	if(l>r)
    		return 0;
    	int id=query(l,r);
    	long long ans=0,tmp=1LL*(id-l)*R;
    	if(1LL*be+1LL*tmp>E)
    		ans=solve(l,id-1,be,E),be=E;
    	else
    		be+=tmp;
    	tmp=1LL*(r-id+1)*R;
    	if(tmp<en)
    		en-=tmp;
    	else
    		ans+=solve(id+1,r,R,en),en=0;
    	ans+=1LL*(be-en)*v[id];
    	return ans;
    }
    
    signed main(void){
    	scanf("%d",&cas);
    	while(cas--){
    		scanf("%d%d%d",&E,&R,&n);
    		for(int i=1;i<=n;i++)
    			scanf("%d",&v[i]);
    		init();printf("%lld
    ",solve(1,n,E,0));
    	}
    	return 0;
    }
    

      


    By NeighThorn

  • 相关阅读:
    hdu 4027 Can you answer these queries? 线段树
    ZOJ1610 Count the Colors 线段树
    poj 2528 Mayor's posters 离散化 线段树
    hdu 1599 find the mincost route floyd求最小环
    POJ 2686 Traveling by Stagecoach 状压DP
    POJ 1990 MooFest 树状数组
    POJ 2955 Brackets 区间DP
    lightoj 1422 Halloween Costumes 区间DP
    模板 有源汇上下界最小流 loj117
    模板 有源汇上下界最大流 loj116
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6516842.html
Copyright © 2011-2022 走看看