zoukankan      html  css  js  c++  java
  • 「BZOJ4842」Delight for a Cat

    题目简述

    有一个人,进行(n)个小时的活动。
    每个活动要么是睡觉((s)),要么是打隔膜((e))。
    规定任意一段连续的(k)个小时,至少(t_1)小时是睡觉,至少(t_2)小时是打隔膜。
    对于第(i)个小时,睡觉的收益是(s_i),打隔膜的收益是(e_i),问最大收益。
    $ 1 leq k leq n leq 10^3 $

    题目解法

    (Part 1)

    我们假设初始每一个小时全都是睡觉,收益为(sum_{i=1}^{n}s_i)
    之后我们就是选一些小时变成打隔膜,每选一个,单个收益是(e_i - s_i)
    我们设(x_i)表示第i个小时要不要变成打隔膜。
    我们设(sum_i=sum_{j=i}^{k+i-1}x_j),那么有如下方程:

    [egin{cases} t_2 leq sum_1 leq k-t_1 \ t_2 leq sum_2 leq k-t_1 \ t_2 leq sum_3 leq k-t_1\ dots\ t_2 leq sum_{n-k+1} leq k-t_1 end{cases} ]

    整理整理,我们再引入两种变量,将不等式变成等式:

    [egin{cases} sum_1 = t_2 + y_1 \ sum_1 = k - t_1 - z_1 \ sum_2 = t_2 + y_2 \ sum_2 = k - t_1 - z_2 \ sum_3 = t_2 + y_3 \ sum_3 = k - t_1 - z_3 \ dots \ sum_{n-k+1} = t_2 + y_{n-k+1} \ sum_{n-k+1} = k - t_1 - z_{n-k+1} \ end{cases} ]

    我们对式子做差分,并且将所有变量的符号都变成正号,可以得到:

    [egin{cases} sum_1 = y_1 + t_2 \ y_1 + z_1 = (k - t_1 - t_2) \ x_{k+1} + (k - t_1 - t_2) = x_1 + y_2 + z_1 \ y_2 + z_2 = (k - t_1 - t_2) \ x_{k+2} + (k - t_1 - t_2) = x_2 + y_3 + z_2 \ y_3 + z_3 = (k - t_1 - t_2) \ ... \ x_{n} + (k - t_1 - t_2) = x_{n-k} + y_{n-k+1} + z_{n-k} \ y_{n-k+1} + z_{n-k+1} = (k - t_1 - t_2) \ k - t_1 = z_{n-k+1} + sum_{n-k+1} end{cases} ]

    然后我们就发现这个式子非常优美,于是我们就可以建图了。
    而且因为我们每一个(x_i)是带费用的,所以要建费用流的图。

    (Part 2)

    这是老套路了,因为每一个变量都是等号左右各出现一次。
    所以我们可以将每一个等号看成一个点,每一个变量看成一条边,
    对于每一个等式,我们将等号左侧看作流入,右侧看作流出,
    对于每一条边,容量就是这个变量的上下界了(当然,就像这道题,下界一般为(0))。
    对于常数项,如果是流入,就从(S)连入,否则就连向(T),容量是常数项的值。
    特殊的,对于这道题,因为每一个(x)变量是有费用的,
    所以我们对于(x_i)的边,要赋一个(e_i-s_i)的费用。
    之后就是最大费用最大流的事了。

    蒟蒻代码

    #include <bits/stdc++.h>
    
    using namespace std;
    
    int read() {
      int res = 0;
      char c = getchar();
      while (!isdigit(c)) c = getchar();
      while (isdigit(c)) res = res * 10 + c - '0', c = getchar();
      return res;
    }
    
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    
    namespace Max_flow {
    const int maxn = 1e4 + 4;
    const int inf_1 = 0x3f3f3f3f;
    const ll inf_2 = 0x3f3f3f3f3f3f3f3f;
    queue<int> que;
    int S, T, e_cnt, head[maxn], pre[maxn][2];
    int nxt[maxn], to[maxn], flow[maxn], vis[maxn];
    ll cost[maxn], dis[maxn];
    void init(int _S, int _T) {
      S = _S, T = _T, e_cnt = -1;
      for (int i = S; i <= T; i++) head[i] = -1;
    }
    void Add(int u, int v, int _flow, ll _cost) {
      //  cerr << "Add(" << u << ", " << v << ", " << _flow << ", " << _cost << ")
    ";
      nxt[++e_cnt] = head[u], head[u] = e_cnt, to[e_cnt] = v;
      flow[e_cnt] = _flow, cost[e_cnt] = _cost;
      nxt[++e_cnt] = head[v], head[v] = e_cnt, to[e_cnt] = u;
      flow[e_cnt] = 0, cost[e_cnt] = -_cost;
    }
    bool bfs() {
      while (!que.empty()) que.pop();
      for (int i = S; i <= T; i++) pre[i][0] = pre[i][1] = 0;
      for (int i = S; i <= T; i++) vis[i] = 0;
      for (int i = S; i <= T; i++) dis[i] = inf_2;
      dis[S] = 0, que.push(S), vis[S] = 1;
      while (!que.empty()) {
        int now = que.front();
        vis[now] = 0, que.pop();
        for (int i = head[now]; ~i; i = nxt[i]) {
          if (flow[i] > 0 && dis[to[i]] > dis[now] + cost[i]) {
            dis[to[i]] = dis[now] + cost[i];
            pre[to[i]][0] = now, pre[to[i]][1] = i;
            if (!vis[to[i]]) que.push(to[i]), vis[to[i]] = 1;
          }
        }
      }
      return dis[T] != inf_2;
    }
    ll Min_cost() {
      ll res = 0;
      while (bfs()) {
        int New_flow = 0x3f3f3f3f;
        for (int i = T; i != S; i = pre[i][0])
          New_flow = min(New_flow, flow[pre[i][1]]);
        res += dis[T] * New_flow;
        for (int i = T; i != S; i = pre[i][0]) flow[pre[i][1]] -= New_flow;
        for (int i = T; i != S; i = pre[i][0]) flow[pre[i][1] ^ 1] += New_flow;
      }
      return res;
    }
    }  // namespace Max_flow
    using Max_flow::Add;
    
    const int maxn = 1e3 + 3;
    int N, K, t_1, t_2, _s[maxn], _e[maxn], id[maxn];
    ll Hahawang_answer = 0;
    
    int main() {
      freopen("a.in", "r", stdin);
      freopen("a.out", "w", stdout);
      N = read(), K = read(), t_1 = read(), t_2 = read();
      for (int i = 1; i <= N; i++) _s[i] = read();
      for (int i = 1; i <= N; i++) _e[i] = read();
      for (int i = 1; i <= N; i++) Hahawang_answer += _s[i];
      Max_flow::init(0, (N - K + 1) * 2 + 2);
      const int inf = 0x3f3f3f3f, dot_num = (N - K + 1) << 1 | 1;
      for (int i = 1; i <= N - K + 1; i++) Add(i << 1 | 1, i << 1, inf, 0);
      for (int i = 1; i <= N - K + 1; i++) Add((i - 1) << 1 | 1, i << 1, inf, 0);
      for (int i = 1; i <= K; i++) {
        id[i] = Max_flow::e_cnt + 1;
        Add(min(i << 1 | 1, dot_num), 1, 1, -(_e[i] - _s[i]));
      }
      for (int i = 1; i <= N - K; i++) {
        id[K + i] = Max_flow::e_cnt + 1;
        Add(min((i + K) << 1 | 1, dot_num), i << 1 | 1, 1, -(_e[K + i] - _s[K + i]));
      }
      for (int i = 1; i <= N - K + 1; i++) Add(i << 1, Max_flow::T, K - t_1 - t_2, 0);
      for (int i = 1; i <= N - K; i++) Add(Max_flow::S, i << 1 | 1, K - t_1 - t_2, 0);
      Add(1, Max_flow::T, t_2, 0), Add(Max_flow::S, dot_num, K - t_1, 0);
      printf("%lld
    ", Hahawang_answer - Max_flow::Min_cost());
      for (int i = 1; i <= N; i++) putchar(Max_flow::flow[id[i]] ? 'S' : 'E');
      putchar('
    ');
      return 0;
    }
    

    参考文章

    https://www.cnblogs.com/CQzhangyu/p/7894559.html

  • 相关阅读:
    python3 TypeError: a bytes-like object is required, not 'str'
    Centos 安装Python Scrapy PhantomJS
    Linux alias
    Vim vimrc配置
    Windows下 Python Selenium PhantomJS 抓取网页并截图
    Linux sort
    Linux RSync 搭建
    SSH隧道 访问内网机
    笔记《鸟哥的Linux私房菜》7 Linux档案与目录管理
    Tornado 错误 "Global name 'memoryview' is not defined"
  • 原文地址:https://www.cnblogs.com/tacmon52818/p/12712982.html
Copyright © 2011-2022 走看看