51nod 1380"夹克老爷的逢三抽一"(贪心+set)
•参考资料
•题意
从长度为 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
View Code1 #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 }