[COGS1862]种树 解题报告

【问题描述】

A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树。园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n。并且每个位置都有一个美观度Ai,如果在这里种树就可以得到这Ai的美观度。但由于A城市土壤肥力欠佳,两棵树决不能种在相邻的位置(i号位置和i+1号位置叫相邻位置。值得注意的是1号和n号也算相邻位置!)。

最终市政府给园林部门提供了m棵树苗并要求全部种上,请你帮忙设计种树方案使得美观度总和最大。如果无法将m棵树苗全部种上,给出无解信息。

【输入格式】

输入的第一行包含两个正整数n、m。

第二行n个整数Ai。

【输出格式】

输出一个整数,表示最佳植树方案可以得到的美观度。如果无解输出“Error!”,不包含引号。

【样例输入】

7 3

1 2 3 4 5 6 7

【样例输出】

15

【样例输入】

7 4

1 2 3 4 5 6 7

【样例输出】

Error!

【数据规模和约定】

对于全部数据:m<=n;

-1000<=Ai<=1000

N的大小对于不同数据有所不同:

分析:

一、部分分算法:

很容易想到的是N^2的DP。。考试的时候,我就写了这个。

但是。。有一些地方没有注意到,下次要注意:①数组一定要开大一点点,防止越界;判断越界的条件一定要写在&&的前面,防止越界。

二、满分算法:sto——cstdio大神。

这个题解正确性的证明来自类似数规的思想,因为比较困难。。所以,被打上了贪心的标签。

我们可以简单地考虑第一次选择的情况。

若此时最大的数为,则在最优解中,易知若不选,则必同时被选,因为若没有同时被选,则显然可以将被选的那个换成得到至少不更差的解。

然后。。。

然后我就放弃了,但是题解没有放弃。

题解非常巧妙地使用了一个等效替换的方式,拜托了被选数不能相邻的限制。

当题解选了一个最大值后,题解在原数列中删去那三个数,并同时加入一个数,并用其替代掉原数列中三个数,维护其在原数列中相对其他数的位置(双向链表)。

这样的话,就相当于在剩下n-2个数中再选m-1个数;并且我们可以发现ak对数量的贡献依然为1,正如一个普通的数一样。既然其满足如此多地性质,我们不禁想要假设在第二步操作中其依然满足此性质。

综上,一个完整的贪心策略(辅以堆+双向链表)便脱颖而出了。

这种神题往往是能给我们一些启示的:

②复杂的问题往往是由简单的问题变形或组合而来的,在面对复杂的问题时从简单的问题出发往往可以获取一些灵感。

③当面对题目不知所措时,发掘题目中的一些性质往往是解题的黄金之匙:诸如可逆性、对称性、等效性等等,尤其是一些奇怪的性质,绝对是破题的关键;而思考的方向也往往围绕着最值、特殊点等等进行,盲目探索只会消磨时间。

#include<iostream>
using namespace std;
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define size 200001
int heap[size],heapsize=1,point[size],a[size],l[size],r[size];
inline void down(int x){
	int now=x,next=x<<1;
	//cout<<"D:"<<heap[x]<<endl;
	while(next<heapsize){
		if(next+1<heapsize&&a[heap[next+1]]>a[heap[next]])++next;
		if(a[heap[now]]>a[heap[next]]){/*
			for(int i=1;i<heapsize;++i)
				printf("%d(%d) ",heap[i],a[heap[i]]);
			cout<<endl;*/
			return;
		}
		//cout<<"(D)"<<heap[now]<<":"<<now<<"->"<<next<<endl;
		swap(heap[now],heap[next]);
		swap(point[heap[now]],point[heap[next]]);
		now=next,next<<=1;
	}
}
inline void up(int x){
	int now=x,next=x>>1;
	//cout<<"U:"<<heap[x]<<endl;
	while(next){
		if(a[heap[next]]>a[heap[now]]){/*
			for(int i=1;i<heapsize;++i)
				printf("%d(%d) ",heap[i],a[heap[i]]);
			cout<<endl;*/
			return;
		}
		//cout<<"(U)"<<heap[now]<<":"<<now<<"->"<<next<<endl;
		swap(heap[now],heap[next]);
		swap(point[heap[next]],point[heap[now]]);
		now=next,next>>=1;
	}
}
char * ptr=(char *)malloc(10000000);
inline void in(int &x){
	bool flag=0;
	while(*ptr<'0'||*ptr>'9')
		if(*ptr++=='-')
			flag=1;
	x=0;
	while(*ptr>47&&*ptr<58)x=x*10+*ptr++-'0';
	if(flag)x=-x;
}
int main(){
	freopen("nt2011_tree.in","r",stdin);
	freopen("nt2011_tree.out","w",stdout);
	int N,M,i,ans=0;
	fread(ptr,1,10000000,stdin);
	in(N),in(M);
	if(N<M<<1){
		printf("Error!");
		return 0;
	}
	for(i=0;i<N;++i)in(a[i]);
	for(i=N-2;i;--i)
		l[i]=i-1,r[i]=i+1;
	l[0]=N-1,r[0]=1,l[N-1]=N-2,r[N-1]=0;
	for(i=0;i<N;++i){
		point[i]=heapsize;
		heap[heapsize]=i;
		up(heapsize++);
		down(point[i]);
	}/*
	printf("\n-----------0----------\n");
	for(int i=1;i<heapsize;++i)
		printf("%d(%d) ",heap[i],a[heap[i]]);*/
	while(M--){
		ans+=a[heap[1]];
		//cout<<heap[1]<<":"<<l[heap[1]]<<" "<<r[heap[1]]<<endl;

		heap[point[l[heap[1]]]]=heap[--heapsize];
		point[heap[heapsize]]=point[l[heap[1]]];
		up(point[heap[heapsize]]);
		down(point[heap[heapsize]]);

		heap[point[r[heap[1]]]]=heap[--heapsize];
		point[heap[heapsize]]=point[r[heap[1]]];
		up(point[heap[heapsize]]);
		down(point[heap[heapsize]]);

		a[heap[1]]=a[l[heap[1]]]+a[r[heap[1]]]-a[heap[1]];
		l[heap[1]]=l[l[heap[1]]];
		r[heap[1]]=r[r[heap[1]]];
		l[r[heap[1]]]=heap[1];
		r[l[heap[1]]]=heap[1];
		down(1);

		/*printf("-----------%d----------\n",M);
		for(int i=1;i<heapsize;++i)
			printf("%d(%d) ",heap[i],a[heap[i]]);
		cout<<endl;*/
	}
	printf("%d",ans);
}
时间: 2024-10-05 02:37:18

[COGS1862]种树 解题报告的相关文章

Problem A: 种树 解题报告

Problem A: 种树 Description 很久很久以前,一个蒟蒻种了一棵会提问的树,树有\(n\)个节点,每个节点有一个权值,现在树给出\(m\)组询问,每次询问两个值:树上一组点对\((x,y)\)简单路径上不同权值的数量以及权值的\(\max\)为多少 然而某一天毒瘤胖子过来给树浇了点水,询问变成了每次求,一组点对\((x,y)\)简单路径上的不同权值的数量以及权值的\(mex\) 然而又过了两天毒瘤袁稳稳也过来给树浇了点水,询问变成了每次求若干组点对\((x,y)\)简单路径的并

解题报告 之 POJ3057 Evacuation

解题报告 之 POJ3057 Evacuation Description Fires can be disastrous, especially when a fire breaks out in a room that is completely filled with people. Rooms usually have a couple of exits and emergency exits, but with everyone rushing out at the same time

hdu 1541 Stars 解题报告

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1541 题目意思:有 N 颗星星,每颗星星都有各自的等级.给出每颗星星的坐标(x, y),它的等级由所有比它低层(或者同层)的或者在它左手边的星星数决定.计算出每个等级(0 ~ n-1)的星星各有多少颗. 我只能说,题目换了一下就不会变通了,泪~~~~ 星星的分布是不是很像树状数组呢~~~没错,就是树状数组题来滴! 按照题目输入,当前星星与后面的星星没有关系.所以只要把 x 之前的横坐标加起来就可以了

【百度之星2014~初赛(第二轮)解题报告】Chess

声明 笔者最近意外的发现 笔者的个人网站http://tiankonguse.com/ 的很多文章被其它网站转载,但是转载时未声明文章来源或参考自 http://tiankonguse.com/ 网站,因此,笔者添加此条声明. 郑重声明:这篇记录<[百度之星2014~初赛(第二轮)解题报告]Chess>转载自 http://tiankonguse.com/ 的这条记录:http://tiankonguse.com/record/record.php?id=667 前言 最近要毕业了,有半年没做

2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告

2016 第七届蓝桥杯 c/c++ B组省赛真题及解题报告 勘误1:第6题第4个 if最后一个条件粗心写错了,答案应为1580. 条件应为abs(a[3]-a[7])!=1,宝宝心理苦啊.!感谢zzh童鞋的提醒. 勘误2:第7题在推断连通的时候条件写错了,后两个if条件中是应该是<=12 落了一个等于号.正确答案应为116. 1.煤球数目 有一堆煤球.堆成三角棱锥形.详细: 第一层放1个, 第二层3个(排列成三角形), 第三层6个(排列成三角形), 第四层10个(排列成三角形). -. 假设一共

[noip2011]铺地毯(carpet)解题报告

最近在写noip2011的题,备战noip,先给自己加个油! 下面是noip2011的试题和自己的解题报告,希望对大家有帮助,题目1如下 1.铺地毯(carpet.cpp/c/pas) [问题描述]为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有n 张地毯,编号从1 到n.现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上.地毯铺设完成后,组织者想知道覆盖地面某个点的最上面的那张地毯的

ACdream 1203 - KIDx&#39;s Triangle(解题报告)

KIDx's Triangle Time Limit: 2000/1000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others) Submit Statistic Next Problem Problem Description One day, KIDx solved a math problem for middle students in seconds! And than he created this problem. N

解题报告 之 CodeForces 91B Queue

解题报告 之 CodeForces 91B Queue Description There are n walruses standing in a queue in an airport. They are numbered starting from the queue's tail: the 1-st walrus stands at the end of the queue and the n-th walrus stands at the beginning of the queue.

解题报告 之 POJ1226 Substrings

解题报告 之 POJ1226 Substrings Description You are given a number of case-sensitive strings of alphabetic characters, find the largest string X, such that either X, or its inverse can be found as a substring of any of the given strings. Input The first li