• CF321E Ciel and Gondolas


    题意:给定序列,将其分成k段。如果[l, r]在一段,那么每对不相同的i,j∈[l, r]都会有ai,j的代价。求最小总代价。

    解:提供两种方案。第三种去bzoj贞鱼的n²算法。

    决策单调性优化:

    对于两个转移点j1 < j2,若在某个点i上j2更优,则i后面的j2全部更优。这就是决策单调性。

    有两种写法。一种是维护决策栈(???),我自己YY了一个线段树写法WA飞了。

    还有一种是分治。对于一段待转移的区间[l, r],它们的最优转移来自于[L, R]

    则对于mid = (l + r) >>1,我们扫一遍[L, R],得到mid的最优转移p

    然后分治下去。

     1 #include <cstdio>
     2 #include <cstring>
     3 
     4 const int N = 4010, K = 810, INF = 0x3f3f3f3f;
     5 
     6 inline void read(int &x) {
     7     x = 0;
     8     char c = getchar();
     9     while(c < '0' || c > '9') {
    10         c = getchar();
    11     }
    12     while(c >= '0' && c <= '9') {
    13         x = (x << 3) + (x << 1) + c - 48;
    14         c = getchar();
    15     }
    16     return;
    17 }
    18 
    19 int f[N][K], n, k, a[N][N];
    20 int tag[N], turn;
    21 
    22 inline void exmin(int &a, int b) {
    23     a > b ? a = b : 0;
    24     return;
    25 }
    26 
    27 void solve(int L, int R, int l, int r) {
    28     if(R < L || r < l) return;
    29     //printf("solve %d %d -> %d %d 
    ", L, R, l, r);
    30     if(L == R) {
    31         for(int i = l; i <= r; i++) {
    32             f[i][turn] = f[R][turn - 1] + a[i][R + 1];
    33             //printf("f %d %d = %d + %d 
    ", i, turn, f[R][turn - 1], a[i][R + 1]);
    34         }
    35         return;
    36     }
    37     int mid = (l + r) >> 1, p = L;
    38     for(int i = L; i < mid && i <= R; i++) {
    39         if(f[mid][turn] > f[i][turn - 1] + a[mid][i + 1]) {
    40             p = i;
    41             f[mid][turn] = f[i][turn - 1] + a[mid][i + 1];
    42             //printf("f %d %d = %d from %d 
    ", mid, turn, f[mid][turn], p);
    43         }
    44     }
    45     solve(L, p, l, mid - 1);
    46     solve(p, R, mid + 1, r);
    47     return;
    48 }
    49 
    50 int main() {
    51 
    52     //freopen("in.in", "r", stdin);
    53     //freopen("my.out", "w", stdout);
    54 
    55     read(n); read(k);
    56     for(register int i = 1; i <= n; i++) {
    57         for(register int j = 1; j <= n; j++) {
    58             read(a[i][j]);
    59             if(i < j) a[i][j] = 0;
    60         }
    61     }
    62     for(register int i = 1; i <= n; i++) {
    63         for(register int j = n; j >= 1; j--) {
    64             a[i][j] += a[i][j + 1];
    65         }
    66     }
    67     for(register int i = 1; i <= n; i++) {
    68         for(register int j = n; j >= 1; j--) {
    69             a[i][j] += a[i - 1][j];
    70         }
    71     }
    72     memset(f, 0x3f, sizeof(f));
    73     f[0][0] = 0;
    74     for(int j = 1; j <= k; j++) {
    75         turn = j;
    76         //printf("turn = %d 
    ", j);
    77         solve(0, n - 1, 1, n);
    78         /*for(int i = 1; i <= n; i++) {
    79             printf("%d ", f[i][turn]);
    80         }
    81         printf("
    ");*/
    82     }
    83 
    84     printf("%d
    ", f[n][k]);
    85     return 0;
    86 }
    决策单调性优化AC代码

    带权二分:我们假装那个函数是凸的。

    然后按照套路带权二分一波。

    记得一定要让k的变化和D的变化同步,这一点可以通过调整±D来实现。

    之后尽量让k小,l端mid,r端要mid - 1。

     1 #include <cstdio>
     2 #include <algorithm>
     3 
     4 typedef long long LL;
     5 const int N = 4010;
     6 LL INF = 1e17;
     7 
     8 inline void read(LL &x) {
     9     x = 0;
    10     char c = getchar();
    11     while(c < '0' || c > '9') {
    12         c = getchar();
    13     }
    14     while(c >= '0' && c <= '9') {
    15         x = (x << 3) + (x << 1) + c - 48;
    16         c = getchar();
    17     }
    18     return;
    19 }
    20 
    21 int n, k, g[N];
    22 LL f[N], a[N][N], D, ans;
    23 
    24 inline int check(LL mid) {
    25     D = mid;
    26     for(register int i = 1; i <= n; i++) {
    27         f[i] = INF;
    28         for(register int j = 0; j < i; j++) {
    29             if(f[i] > f[j] + a[i][j + 1] - D) {
    30                 f[i] = f[j] + a[i][j + 1] - D;
    31                 g[i] = g[j] + 1;
    32             }
    33             else if(f[i] == f[j] + a[i][j + 1] - D) {
    34                 g[i] = std::min(g[i], g[j] + 1);
    35             }
    36         }
    37     }
    38     ans = f[n];
    39     return g[n];
    40 }
    41 
    42 int main() {
    43     scanf("%d%d", &n, &k);
    44     for(register int i = 1; i <= n; i++) {
    45         for(register int j = 1; j <= n; j++) {
    46             read(a[i][j]);
    47             if(i < j) a[i][j] = 0;
    48         }
    49     }
    50     for(register int i = 1; i <= n; i++) {
    51         for(register int j = n; j >= 1; j--) {
    52             a[i][j] += a[i][j + 1];
    53         }
    54     }
    55     for(register int i = 1; i <= n; i++) {
    56         for(register int j = n; j >= 1; j--) {
    57             a[i][j] += a[i - 1][j];
    58         }
    59     }
    60     //
    61 
    62     LL l = -a[n][1], r = a[n][1];
    63     while(l < r) {
    64         LL mid = (l + r + 1) >> 1;
    65         int t = check(mid);
    66         if(t == k) {
    67             printf("%lld
    ", ans + k * mid);
    68             return 0;
    69         }
    70         if(t < k) l = mid;
    71         else r = mid - 1;
    72     }
    73     check(r);
    74     printf("%lld
    ", ans + k * r);
    75     return 0;
    76 }
    带权二分AC代码
  • 相关阅读:
    Beta版本冲刺第二天
    项目冲刺-第十天
    项目冲刺-第五天
    用例图练习
    软件案例分析(微软必应词典客户端)
    第二次作业——结对项目之需求分析与原型模型设计
    git for windows 入门随笔
    软件工程的实践项目的自我目标
    Android的开发环境的发展演变
    我的软件工程实践的总结
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10409122.html
Copyright © 2020-2023  润新知