so就 (二分答案 dp 贪心)

来源:互联网 发布:口腔医学网络教育 编辑:程序博客网 时间:2024/05/27 14:12

so就

9.11
思路:
明显的dp感觉,但是nk的复杂度又很恼火。当然有一种二分答案然后用dp来check的方法,就贴上代码不细说了。这里还有一种贪心的做法,用一个set来维护最大权值,之后每次从堆里取出堆顶元素,每次贪心的维护k=i时的ans(就只有k次循环),将堆顶元素和相邻的两个元素合并并修改权值,用链表维护相邻的关系,具体的实现还是看代码吧。

#include <iostream>  #include <cstdio>#include <set>#define LL long longusing 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 ; }
原创粉丝点击