51nod 1380:夹克老爷的逢三抽一


1380夹克老爷的逢三抽一
基准时间限制:1秒 空间限制:131072KB 分值:320难度:7级算法题
收藏
取消关注
又到了诺德县的百姓孝敬夹克大老爷的日子,带着数量不等的铜板的村民准时聚集到了村口。
夹克老爷是一位很"善良"的老爷,为了体现他的仁慈,有一套特别的收钱的技巧。
1、让所有的村民排成一队,然后首尾相接排成一个圈。
2、选择一位村民收下他的铜钱,然后放过他左右两边的村民。
3、让上述三位村民离开队伍,并让左右两边的其他村民合拢起来继续围成一个圈。
4、重复执行2、3直到村民全部离开。
夹克老爷的家丁早早的组织村民排成一队并清点了村民人数和他们手里的铜钱数量。
作为夹克老爷的首席师爷,你要负责按照夹克老爷的收钱技巧完成纳贡的任务。
聪明的你当然知道夹克老爷并不像他表现出来的那样仁慈,能否收到最多的钱财决定了你是否能够继续坐稳首席师爷的位置。
今年村民的人数是N,恰巧是3的倍数。


提示:第2步选择村民时不需要按照任何顺序,你可以选择任何一位仍然在队伍里的村民收取他手中的钱财并放走他两侧的村民(这就意味着你无法同时收取到这两位的铜钱了)
Input
第一行1个整数N(3<=N<=10^5-1,N%3==0)
第2-N+1行:每行1个数对应村民i手中的铜钱。(0<=m[i]<=10^9)
Output
一个整数,说明在夹克老爷的收钱规则下你最多能够为夹克老爷搜刮到多少铜钱
Input示例
6
6
2
3
4
5
9
Output示例
13

问题等价于N长的数组中抽取N/3个不相邻的值使得和最大(首尾也不能同时取)

普通的dp方法复杂度n^2会TLE
用贪心,类似最大M子段和的方式
初始全部数字可选状态,进优先队列,弹出最大值,结果中加上选中的最大值,删除最大值左右两边的值,将最大值位置的值修改为左右两边的和减去中间的数重新进入优先队列,循环处理直到拿到要求的数据个数。

以上是官方题解。。。头一次用优先队列做这种题,结果中加上选中的最大值,删除最大值左右两边的值,将最大值位置的值修改为左右两边的和减去中间的数重新进入优先队列,循环处理直到拿到要求的数据个数。这块太巧妙了,直接把算法的时间复杂度搞到了O(n)。
代码:
#include <iostream>  
#include <algorithm>  
#include <cmath>  
#include <vector>  
#include <string>  
#include <cstring>
#include <queue>
#pragma warning(disable:4996)  
using namespace std;

#define impossible -1*(1e9+7)

struct no
{
	long long val;
	int pos;

	friend bool operator<(no n1, no n2)
	{
		return n1.val < n2.val;
	}
}node[100005];

int n;
long long val[100005];

int main()
{
	//freopen("i.txt", "r", stdin);
	//freopen("o.txt", "w", stdout);

	int i, k, temp, out;
	unsigned long long sum;
	no n_temp;
	priority_queue<no>q;

	scanf("%d", &n);

	for (i = 0; i < n; i++)
	{
		scanf("%d", &temp);
		node[i].val = temp;
		node[i].pos = i;
		q.push(node[i]);

		val[i] = temp;
	}

	k = 0;
	sum = 0;
	out = n / 3;
	while (true)
	{
		n_temp = q.top();
		if (n_temp.val <= 0)
			break;
		if (val[n_temp.pos] != impossible)
		{
			q.pop();
			sum += n_temp.val;

			int le = n_temp.pos;
			int ri = n_temp.pos;
			while (val[(le - 1 + n) % n] == impossible)
			{
				le--;
			}
			while (val[(ri + 1 + n) % n] == impossible)
			{
				ri++;
			}

			no nn_temp;
			nn_temp.val = val[(le - 1 + n) % n] + val[(ri + 1 + n) % n ] - n_temp.val;
			nn_temp.pos = n_temp.pos;

			q.push(nn_temp);

			val[n_temp.pos] = nn_temp.val;
			val[(le - 1 +  n) % n] = impossible;
			val[(ri + 1 +  n) % n] = impossible;

			k++;
		}
		else
		{
			q.pop();
		}
		if (k == out)
			break;
	}

	printf("%lld\n", sum);
	//system("pause");
	return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

优质内容筛选与推荐>>
1、从最近租房得出的一个结论
2、rsyslog 配置
3、n-map安装实操
4、MySQL 找回密码
5、日装品牌


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn