• [noip模拟赛2017.7.12]


    内存 256M 时限 1s

    最大和(sum)

    题目描述

    N 个数围成一圈,要求从中选择若干个连续的数(注意每个数最多只能选一次)加起来, 问能形成的最大的和。

    输入格式:

    第一行输入 N,表示数字的个数,第二行输入这 N 个数字。

    输出格式:

    输出最大和。

    样例输入:

    8
    2 -4 6 -1 -4 8 -1 3

    样例输出:

    14

    数据说明:

    40% 1<=N<=300 60% 1<=N<=2000 100% 1<=N<=100000,答案在 longint 范围内。

    题解

    对于链状最大和,显然可以贪心O(n)完成,而环状最大和,只可能在链上或者在两端,如果在两端,显然,中间一段一定是最小子段和,那么我们用总和减去最小链状子段和,即可求得环状的最大子段和

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #define LL long long  
    using namespace std;
    const int Num_Ary=100000;
    int n,a[Num_Ary];
    int mx[Num_Ary],mi[Num_Ary];
    int ans,sum;
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&a[i]),sum+=a[i];
    	for(int i=1;i<=n;i++){
    		mx[i]=max(mx[i-1]+a[i],max(a[i],0));
    		mi[i]=min(mi[i-1]+a[i],min(a[i],0));
    		ans=max(ans,mx[i]);ans=max(ans,sum-mi[i]);
    	}
    	printf("%d",ans);	
    }
    
    

    修剪花卉

    问题背景:

    ZZ对数学饱有兴趣,并且是个勤奋好学的学生,总是在课后留在教室向老师请教一些问题。 一天他早晨骑车去上课,路上见到一个老伯正在修剪花花草草,顿时想到了一个有关修剪花 卉的问题。 于是当日课后,ZZ就向老师提出了这个问题: 一株奇怪的花卉,上面共连有N 朵花,共有N-1条枝干将花儿连在一起,并且未修剪时每 朵花都不是孤立的。 每朵花都有一个“美丽指数”,该数越大说明这朵花越漂亮,也有“美丽指数”为负数的, 说明这朵花看着都让人恶心。 所谓“修剪”,意为:去掉其中的一条枝条,这样一株花就成了两株,扔掉其中一株。 经过一系列“修剪“之后,还剩下最后一株花(也可能是一朵)。 老师的任务就是:通过一系列“修剪”(也可以什么“修剪”都不进行),使剩下的那株(那 朵)花卉上所有花朵的“美丽指数”之和最大。 老师想了一会儿,给出了正解(交大的老师是很牛的~)。ZZ见问题被轻易攻破,相当不爽, 于是又拿来问你。

    输入说明:

    第一行一个整数N(1 ≤ N ≤ 16000)。表示原始的那株花卉上共N 朵花。 第二行有N 个整数,第I个整数表示第I朵花的美丽指数。 接下来N-1行每行两个整数a,b,表示存在一条连接第a 朵花和第b朵花的枝条。 ## 输出说明:
    一个数,表示一系列“修剪”之后所能得到的“美丽指数”之和的最大值。保证绝对值不超 过2147483647。

    样例输入:

    7

    -1 -1 -1 1 1 1 0

    1 4

    2 5

    3 6

    4 7

    5 7

    6 7

    样例输出:

    3

    数据范围:

    对于 60%的数据, 保证N≤1,000 对于 100%的数据,保证 N≤16,000

    题解

    此题略水,直接树型DP,每次返回子数最优值,用来更新ans即可

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #define LL long long  
    using namespace std;
    int n,ans;
    int a[40000],b[40000],nt[40000],p[40000],v[40000],cnt=1;
    void add(int x,int y){
    	a[cnt]=x;b[cnt]=y;
    	nt[cnt]=p[x];p[x]=cnt++;
    }
    bool vis[40000];
    int dfs(int k){
    	int rtn=0;vis[k]=true;
    	for(int i=p[k];i;i=nt[i]){
    		int kk=b[i];
    		if(!vis[kk])
    			rtn=max(rtn,rtn+dfs(kk));
    	}
    	ans=max(ans,rtn+v[k]);
    	return rtn+v[k];
    }
    int main(){
    	freopen("makeup.in","r",stdin);
    	freopen("makeup.out","w",stdout);
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&v[i]);
    	for(int i=1;i<n;i++){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		add(x,y);add(y,x);
    	}
    	dfs(1);
    	printf("%d",ans);
    	return 0;
    }
    
    

    金字塔(pyramid)

    题目描述:

    小 X 来到一个雄奇的金字塔挖宝,但是这是一座被诅咒的金字塔,小 X 必须马上逃离这里, 否则小 X 就会被埋在金字塔里,但他不希望此行落空。 现在小 X 面前有 N+1 种财宝,每种财宝都有一个价值。第一种财宝重量为 0,第二种财宝 重量为 1,总之第 I 种财宝重量为 I-1。现在小 X 希望拿走 N+M 个物品,但是这 M+N 个物品 总重量不能超过 N。小 X 希望能获得最大的价值。你能帮帮他吗? 由于金字塔跟小 X 一样牛,所以每种财宝无限个。

    输入格式:

    第一行两个正整数 N,M 第二行 N+1 个整数,第 I 个整数代表了第 I 种财宝的价值

    输出格式:

    一个数,表示最大利润。

    样例输入:

    5 3

    4 7 2 5 -3 6

    样例输出:

    47

    数据范围:

    10%满足 N,M<=10 40%满足 N,M<=100 100%满足 N,M<=3000abs(财宝价值)<=1000

    题解

    杂技DP,我们考虑重量为0的物品,它的存在不受重量的限制,可作为本题的突破口,因为任何一种状态,要想满足题设要求,必须要重量为0的那个物品填充数量,我们记重量为i这个状态所拿的物品数量(不计重量为0的)为t[i],价值为f[i],容易得到,最终价值w[i]=f[i]+(m+n-t[i])*v[0],转移方程时,选取使w[i]最大的方案进行转移即可

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #define LL long long  
    #define INF (1<<30)
    using namespace std;
    int n,m,v[10010];
    int f[10010],t[10010],ans=-INF;
    int main(){
    	freopen("pyramid.in","r",stdin);
    	freopen("pyramid.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)f[i]=-INF;
    	for(int i=0;i<=n;i++)
    		scanf("%d",&v[i]);
    	for(int i=1;i<=n;i++){
    		for(int j=i;j<=n;j++){
    			if(f[j]+(m+n-t[j])*v[0]<f[j-i]+v[i]+(m+n-t[j-i]-1)*v[0]){
    				t[j]=t[j-i]+1;
    				f[j]=f[j-i]+v[i];
    			}
    		}
    	}
    	for(int i=0;i<=n;i++)
    		ans=max(ans,(m+n-t[i])*v[0]+f[i]);
    	printf("%d",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    题解文本生成器
    莫比乌斯反演学习笔记
    数论整除分块
    线段树
    AC自动机学习笔记
    game theory
    Android 学习 笔记_05. 文件下载
    Android 学习 笔记_08. 广播机制
    Android 学习 笔记_07. XML文件解析
    Android 学习 笔记_09. WIFI网络操作
  • 原文地址:https://www.cnblogs.com/Anoxiacxy/p/7183830.html
Copyright © 2020-2023  润新知