so就
9.11
思路:
明显的dp感觉,但是nk的复杂度又很恼火。当然有一种二分答案然后用dp来check的方法,就贴上代码不细说了。这里还有一种贪心的做法,用一个set来维护最大权值,之后每次从堆里取出堆顶元素,每次贪心的维护k=i时的ans(就只有k次循环),将堆顶元素和相邻的两个元素合并并修改权值,用链表维护相邻的关系,具体的实现还是看代码吧。
#include <iostream>
#include <cstdio>
#include <set>
#define LL long long
using namespace std;
const int N = 100010;
int n, k;
LL ans, a[N];
int pre[N], nex[N];
struct node {
LL w;
int id;
friend bool operator <(const node & a, const node & b){ return a.w==b.w ? a.id<b.id : a.w>b.w;}
};
set<node> q;
void solve() {
while( k-- ){
node top = *q.begin();
q.erase((node){ top.w, top.id});
ans += (LL)a[top.id];
a[top.id] = a[pre[top.id]] + a[nex[top.id]] - a[top.id];
if( pre[top.id] ) q.erase((node){ a[pre[top.id]], pre[top.id]});
if( nex[top.id] ) q.erase((node){ a[nex[top.id]], nex[top.id]});
q.insert((node){ a[top.id], top.id});
if( pre[pre[top.id]] ) nex[pre[pre[top.id]]] = top.id;
if( nex[nex[top.id]] ) pre[nex[nex[top.id]]] = top.id;
pre[top.id] = pre[pre[top.id]];
nex[top.id] = nex[nex[top.id]];
}
}
int main(){
freopen ("so.in", "r", stdin);
freopen ("so.out", "w", stdout);
scanf("%d%d", &n, &k);
a[0] = (LL)-1e17;
for(int i=1; i<=n; i++){
scanf("%I64d", &a[i]);
pre[i] = i-1, nex[i] = i+1;
q.insert((node){ a[i], i});
}
pre[1] = 0; nex[n] = 0;
solve();
printf("%I64d", ans);
return 0;
}
dp
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std ;
typedef long long LL ;
int n, k ;
const int MAXN = 100010 ;
int a[MAXN];
LL b[MAXN] ;
LL dp[MAXN][2] ;
int minp[MAXN][2] ;
int check(LL x) {
for (int i = 1; i <= n; i ++) b[i] = x + a[i] ;
for (int i = 1; i <= n; i ++) {
dp[i][0] = dp[i - 1][0], minp[i][0] = minp[i - 1][0] ;
if (dp[i - 1][1] > dp[i][0]) dp[i][0] = dp[i - 1][1], minp[i][0] = minp[i - 1][1] ;
else if (dp[i - 1][1] == dp[i][0] && minp[i - 1][1] > minp[i][0]) minp[i][0] = minp[i - 1][1] ;
dp[i][1] = dp[i - 1][0] + b[i], minp[i][1] = minp[i - 1][0] + 1 ;
}
if (dp[n][1] > dp[n][0]) return minp[n][1] ;
if (dp[n][1] == dp[n][0]) return min(minp[n][1], minp[n][0]) ;
return minp[n][0] ;
}
LL Calc(LL x) {
for (int i = 1; i <= n; i ++) b[i] = a[i] + x;
for (int i = 1; i <= n; i ++) {
dp[i][0] = dp[i - 1][0], minp[i][0] = minp[i - 1][0] ;
if (dp[i - 1][1] > dp[i][0]) dp[i][0] = dp[i - 1][1], minp[i][0] = minp[i - 1][1] ;
else if (dp[i - 1][1] == dp[i][0] && minp[i - 1][1] > minp[i][0]) minp[i][0] = minp[i - 1][1] ;
dp[i][1] = dp[i - 1][0] + b[i], minp[i][1] = minp[i - 1][0] + 1 ;
}
return max(dp[n][0], dp[n][1]) - 1LL * x * k ;
}
int main() {
freopen("so.in", "r", stdin) ;
freopen("so.out", "w", stdout) ;
scanf("%d%d", &n, &k) ;
for (int i = 1; i <= n; i ++) scanf("%d", &a[i]) ;
LL l = - 10000000000LL, r = 10000000000LL ;
while (l < r) {
LL mid = (1LL * l + r + 20000000000LL) / 2 + 1 - 10000000000LL ;
if (check(mid) > k) r = mid - 1 ;
else l = mid ;
}
cout << Calc(l) << endl ;
}