51nod 1380"夹克老爷的逢三抽一"(贪心+set)

 

传送门

 

•参考资料

  [1]:51Nod-1380-夹克老爷的逢三抽一

•题意

  从长度为 n 的数组中抽取 $\frac{n}{3}$ 个不相邻的值使得加和最大(首尾也不能同时取)

•题解

  贪心选择当前最大值 $a_{max}$,同时删掉包含 $a_{max}$ 在内的其左($a_l$)和其右($a_r$) 这三个数;

  但是,还有一种可能是 $a_l + a_r > a_{max}$,那么,我们就需要选择 $a_l,a_r$ 这两个数,而不选择 $a_{max}$ 这个数;

  所以,我们还需要将 $a_l+a_r-a_{max}$ 放入待考虑序列中;

  每次删除其左和其右的数时,可以用两个数组 $L,R$ 来记录当前位于其左和其右的位置下标;

•Code

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define pll pair<ll ,ll >
 5 #define F first
 6 #define S second
 7 const int maxn=1e5+50;
 8 
 9 int n;
10 ll a[maxn];
11 int L[maxn];
12 int R[maxn];
13 set<pll >_set;
14 
15 void Del(int x)
16 {
17     _set.erase({a[x],x});
18     L[R[x]]=L[x];
19     R[L[x]]=R[x];
20 }
21 ll Solve()
22 {
23     for(int i=1;i <= n;++i)
24     {
25         L[i]=(i-1+n-1)%n+1;
26         R[i]=i%n+1;
27         _set.insert({a[i],i});
28     }
29 
30     ll ans=0;
31     for(int i=1;i <= n/3;++i)
32     {
33         ans += _set.rbegin()->F;
34 
35         int x=_set.rbegin()->S;
36         ll b=a[L[x]];
37         ll c=a[x];
38         ll d=a[R[x]];
39         
40         Del(L[x]);
41         Del(R[x]);
42         _set.erase({a[x],x});
43         
44         a[x]=b+d-c;
45         _set.insert({a[x],x});
46     }
47     return ans;
48 }
49 int main()
50 {
51     scanf("%d",&n);
52     for(int i=1;i <= n;++i)
53         scanf("%lld",a+i);
54     printf("%lld\n",Solve());
55 
56     return 0;
57 }
View Code

 

posted @ 2019-10-23 10:07  HHHyacinth  阅读(188)  评论(0编辑  收藏  举报