题目大意:
题目链接:https://www.luogu.org/problemnew/show/P1484
有
n
n
n个点,选择其中互不相邻的不超过
m
m
m个点,使得点权和最大。
思路:
思维题。
考虑贪心。如果我们第一次选择了最大值点
i
i
i,那么选择两个点时,要么点
i
−
1
i-1
i−1和点
i
+
1
i+1
i+1一起选,要么两个都不选。
如果我们选择点 i − 1 i-1 i−1和点 x ( x ≠ i + 1 ) x(x≠i+1) x(x̸=i+1),那么贪心思想, a [ i − 1 ] + a [ x ] a[i-1]+a[x] a[i−1]+a[x]必然大于任意 a [ q ] + a [ p ] a[q]+a[p] a[q]+a[p]。但是当 p = i , q = x p=i,q=x p=i,q=x时, a [ i − > 1 ] + a [ x ] a[i-> 1]+a[x] a[i−>1]+a[x]肯定小于 a [ i ] + a [ x ] a[i]+a[x] a[i]+a[x](因为一开始 a [ i ] a[i] a[i]是最大的)。矛盾。
证毕
如果不选择
a
[
i
−
1
]
a[i-1]
a[i−1]和
a
[
i
+
1
]
a[i+1]
a[i+1],那么就是一个正常的贪心。但是如果选择
a
[
i
−
1
]
a[i-1]
a[i−1]和
a
[
i
+
1
]
a[i+1]
a[i+1]的话,就需要满足可撤销。
如果我们把
a
[
i
]
a[i]
a[i]的值更改成
a
[
i
−
1
]
+
a
[
i
+
1
]
−
a
[
i
]
a[i-1]+a[i+1]-a[i]
a[i−1]+a[i+1]−a[i],再次选择
a
a
a数组中最大值,那么
a
n
s
ans
ans就等于
a
[
i
]
+
a
[
i
−
1
]
+
a
[
i
+
1
]
−
a
[
i
]
=
a
[
i
−
1
]
+
a
[
i
+
1
]
a[i]+a[i-1]+a[i+1]-a[i]=a[i-1]+a[i+1]
a[i]+a[i−1]+a[i+1]−a[i]=a[i−1]+a[i+1]!
这样用堆维护最大值,就可以做到 O ( m log n ) O(m\log n) O(mlogn)的复杂度
代码:
#include <queue>
#include <cstdio>
#define mp make_pair
using namespace std;
typedef long long ll;
const int N=500010;
int n,m;
bool p[N];
ll a[N],ans;
priority_queue<pair<ll,int> > q;
struct node
{
int l,r;
}link[N];
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
q.push(mp(a[i],i));
link[i].l=i-1; link[i].r=i+1;
}
while (m--)
{
while (p[q.top().second]) q.pop();
if (q.top().first<0) break;
ans+=q.top().first;
int id=q.top().second;
a[id]=a[link[id].l]+a[link[id].r]-a[id];
p[link[id].l]=p[link[id].r]=1;
link[id].l=link[link[id].l].l; link[link[id].l].r=id;
link[id].r=link[link[id].r].r; link[link[id].r].l=id;
q.pop(); q.push(mp(a[id],id));
}
printf("%lld",ans);
return 0;
}