• CF413C


    正文

    题意:

    给 n 个关卡,每个关卡得分为 ai,有 m 次机会可以选择一
    个关卡通过后不得分,而将现有得分翻倍

    你可以安排关卡的通过顺序和策略,求最大得分.


    分析:

    看到这道题首先想到的就是贪心,贪心不仅是最好想也是最好写的。

    • 开始我们可以确定的是,如果有个关卡不能翻倍,那你只能把他的分值加上;
    • 另外,我们知道,如果基数越大,那他翻倍后的数就越大,
      这也是贪心的核心所在,如果我们想要更大的值,就要先得到更大的基数再把它翻倍,所以我们应先把所有只能加的数加起来在翻倍(因为题目给定分值不会为负数);
    • 还有,在遇到能翻倍的关卡的时候,也要判断一下到底是翻倍后得的分多还是不翻倍加上当前关卡分得的分多。

    知道这些了以后,我们可以写代码了


    做法

    • 我这里是一开始把所有关卡的分全都加上,再减去可以翻倍的关卡的分,作为开始的基数;
    • 然后新开一个数组专门存能翻倍的关卡的分,并从大到小排序,还是遵循了先基数大优先的准则,如果把大的放后面,那他能作为基数扩大后面的值的可能性就会变小,所以先放前面并每次比较加上它后的值与翻倍的值,取较大的那个;
    • 注意:我这里本来想用计数器记录翻倍关卡的数量,在排序时按照它的数量排,但是我这里赋值后关卡分值在数组里的分布是不定的,有的会排不到,所以要把所有的数组全排一遍。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring> 
    #include<cmath>
    #include<algorithm>
    #define maxn 1000010
    
    using namespace std;
    
    long long n,m,a[maxn],b[maxn],c[maxn],cnt,ans;
    
    int cmp(int x,int y){
    	return x>y;
    }
    
    int main(){
    	cin>>n>>m;
    	for(int i=1;i<=n;i++){
    		cin>>a[i];
    		ans+=a[i];
    	}
    	for(int i=1;i<=m;i++){
    		cin>>b[i];
    		for(int j=1;j<=n;j++){
    		    if(b[i]==j){
    		    	c[j]=a[b[i]];
    		    	ans-=a[b[i]];
    		    	cnt++;
    		    } 
    		}
    	}
    	sort(c+1,c+n+1,cmp);
    	for(int i=1;i<=cnt;i++){
    		if(ans*2>=ans+c[i]) ans*=2;
    		else ans+=c[i];
    	}
    	cout<<ans;
    	return 0;
    } 
    

    制作不易,若有错请各位指正

  • 相关阅读:
    log4net 无法输出日志,跟踪发现IsErrorEnabled等,都是Flase
    jquery load加载不了内容
    数据库中的表还是一定要建索引
    最近的项目中用到读卡器,用的华视身份证阅读器,附上SDK使用手册
    背景自动滚动
    理解JavaScript函数(函数和对象的区别和联系)
    代码运行框
    ie8以ie7方式解析
    js开发工具集
    cssZip
  • 原文地址:https://www.cnblogs.com/KnightL/p/13935445.html
Copyright © 2020-2023  润新知