51nod 1380 夹克老爷的逢三抽一 堆 脑洞题

51nod 1380 夹克老爷的逢三抽一
堆 脑洞题
题意 n个人围成一圈
然后每次可以选一个人,得到他的分数,然后他与他相邻的两个人出圈
总共选 n/3次, 保证n是3的倍数

题解
这道怎么说呢,应该比较巧妙吧,你开一个优先队列,大根堆,每次选择优先队列中
最大的数,然后把他左右两个数删掉,
比如 A B C 删掉 B ,那么就把 A+C-B 加入优先队列中,
这其实就是相当于提供了一个后悔的机会,就像网络流中的反向边,
如果在选中这个点的话,就相当于 B+(A+C-B) 然后就相当于 B 这个点 不选 选A C两点
这不恰好是我们想要的吗。如果选了这个数不是最优解,我们可以有一个反悔的机会。
而且选的次数也不会错, 这样时间复杂度就是 O(N log N)

 1 #include <bits/stdc++.h>
 2 #define ll long long
 3 using namespace std ;
 4
 5 const int N = 1e5+11 ;
 6 int n,x,num ;
 7 ll a[N] ;
 8 int l[N],r[N] ;
 9 bool vis[N] ;
10 ll ans ;
11 struct node{
12     ll val ;
13     int id ;
14 };
15 struct cmp{
16     bool operator() (node a,node b)
17     {
18         return a.val < b.val ;
19     }
20 };
21 node p ;
22 priority_queue <node,vector<node>,cmp> Q ;
23
24 inline ll read()
25 {
26     ll x = 0 , f = 1 ;
27     char ch = getchar() ;
28     while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘) f = -1 ; ch = getchar() ; }
29     while(ch>=‘0‘&&ch<=‘9‘) { x = x * 10+ch-48 ; ch = getchar() ; }
30     return x * f ;
31 }
32
33 int main()
34 {
35     n = read() ;
36     for(int i=1;i<=n;i++)
37     {
38         a[ i ] = read() , l[ i ] = i-1 ,r[ i ] = i+1 ;
39         p.id = i ; p.val = a[ i ] ;
40         Q.push( p ) ;
41     }
42     l[ 1 ] = n ; r[ n ] = 1 ;
43     while(!Q.empty())
44     {
45         p = Q.top() ;
46         Q.pop() ;
47         x = p.id ;
48         if(vis[x]) continue ;
49
50         ans+=p.val ;
51         num++ ;
52         vis[ l[x] ] = 1 ;
53         vis[ r[x] ] = 1 ;
54         p.id = x ; a[ x ] = a[ l[x] ] + a[ r[x] ] -a[x] ;
55         p.val = a[ x ] ;
56         Q.push(p) ;
57         int L = l[l[x]] , R = r[r[x]] ;
58         l[x] = L ;  r[x] = R ;
59         r[L] = x ;  l[R] = x ;
60         if(num*3==n) break ;
61     }
62     printf("%lld",ans) ;
63     return 0 ;
64 }
时间: 2024-10-18 12:46:00

51nod 1380 夹克老爷的逢三抽一 堆 脑洞题的相关文章

51Nod 1380 夹克老爷的逢三抽一

Description 一开始有一个环,可以选择删除一个元素获得他的权值,同时删除与它相邻的两个元素,其他元素重新形成环,问能获得的最大价值. Sol 堆+贪心. 一开始从堆中加入所有元素,然后取出一个元素之后,加入他两边的元素之和-该位置的权值,并把左右两点删除. 一直到取出 \(\frac {n} {3}\) 个元素即可,左右元素可以用链表维护. 这样取出一个元素了以后可以进行反悔的操作,获得另外两个权值. xyx大爷说只要不相邻那么元素个数使得他必然有一种合法的删除方案. Code #in

51nod 1378 夹克老爷的愤怒(树形DP+贪心)

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1378 大致题意: 一棵1e5节点的树,安放某些位置,一个位置可以控制距他的距离不超过K的所有节点, 输入树和K,求控制全图(所有节点)需要安放最少的个数 思路: 假如是线性结构,一定是从边界开始每距离2k安放一个,然后最后正好或者再放置一个,这个贪心思路所有人都会. 当是树形结构时,仍然用那个贪心,显然安放的位置越靠近根节点控制的其他节点数越多,所以这里必须从

[51nod] 1378 夹克老爷的愤怒 #树形DP

1378 夹克老爷的愤怒 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 夹克老爷逢三抽一之后,由于采用了新师爷的策略,乡民们叫苦不堪,开始组织起来暴力抗租. 夹克老爷很愤怒,他决定派家丁常驻村中进行镇压. 诺德县 有N个村庄,编号0 至 N-1,这些村庄之间用N - 1条道路连接起来. 家丁都是经过系统训练的暴力机器,每名家丁可以被派驻在一个村庄,并镇压当前村庄以及距离该村庄不超过K段道路的村庄. 夹克老爷一贯奉行最小成本最大利润的原则,请问要实现对全部村庄

51nod 1378 夹克老爷的愤怒(树型dp+贪心)

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1378 题意: 思路:要想放得少,尽量放在叶子节点处,叶子节点处点比较多. 从叶子节点开始往上回溯,到第k个点时就放置一名家丁,用dp[x]来记录状态,若为负,则表示该节点及其子树所需要家丁的最远距离,若为正,则表示该节点及其子树中家丁还能镇压的最大距离. 1 #include<cstdio> 2 #include<cstring> 3 #include&l

51Nod 1378 夹克老爷的愤怒

Description 一棵树,可以进行染色,被染色的点可以控制与它距离不超过 \(k\) 的所有点,问控制整棵树最少需要染几个点. Sol 贪心. 记录一下最深的未染色点和最浅的染色点,判断一下能否在子树中就完成,不能的话就把权值赋成最深未染色点深度+1,能的话就赋成染色点深度+1. 需要特判一下根. Code #include<cstdio> #include<vector> #include<ctime> #include<cstdlib> #incl

PAT:1001. A+B Format (20)(数组存储,逢三加“,”) AC

#include<stdio.h> int main() { int a,b; scanf("%d%d",&a,&b); int sum=a+b; if(sum<0) { printf("-"); sum=-sum; } int arr[30]; int i=0; do { arr[i]=sum%10; sum/=10; ++i; }while(sum!=0); for(int j=i-1 ; j>=0 ; --j) { pr

第三次作业第四题

根据邹欣老师的教材相关内容,确定小组成员的角色,细化项目需求.时间计划.列出产品积压工作项和预计开发时间 一.小组成员分工明细如下: 二.细化项目需求: 项目需求说明书已在上周完成,github上需求文档的链接如下 https://github.com/vrfighter/Arithmetic/blob/master/document/%E5%9B%9B%E5%88%99%E8%BF%90%E7%AE%97%E9%9C%80%E6%B1%82%E6%8A%A5%E5%91%8A.md 三.项目预

16级第三周寒假作业E题

兵队列训练问题 TimeLimit:1000MS  MemoryLimit:32768KB 64-bit integer IO format:%I64d Problem Description 某部队进行新兵队列训练,将新兵从一开始按顺序依次编号,并排成一行横队,训练的规则如下:从头开始一至二报数,凡报到二的出列,剩下的向小序号方向靠拢,再从头开始进行一至三报数,凡报到三的出列,剩下的向小序号方向靠拢,继续从头开始进行一至二报数...,以后从头开始轮流进行一至二报数.一至三报数直到剩下的人数不超

51Nod 1083 矩阵取数问题(矩阵取数dp,基础题)

1083 矩阵取数问题 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题 一个N*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励,从左上走到右下,只能向下向右走,求能够获得的最大价值. 例如:3 * 3的方格. 1 3 3 2 1 3 2 2 1 能够获得的最大价值为:11. Input 第1行:N,N为矩阵的大小.(2 <= N <= 500) 第2 - N + 1行:每行N个数,中间用空格隔开,对应格子中奖励的价值.(1 <= N[i]