您的位置:首页 > 其它

so就 (二分答案 dp 贪心)

2017-09-11 15:20 302 查看

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
;
int pre
, nex
;

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
= 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
[1] > dp
[0]) return minp
[1] ;
if (dp
[1] == dp
[0]) return min(minp
[1], minp
[0]) ;
return minp
[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
[0], dp
[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 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: