BJ模拟(1) D1T1 Delight for a Cat

  Delight for a Cat

题目背景:

thoj22

分析:

首先,如果你没有学习过NOI2008的志愿者招募,请先去A掉那道题这里

首先,假设这只猫在所有天数都是睡觉,我们稍后再决策将哪些天数改为吃东西。

我们用 X= 0 表示这只猫在第i天睡觉, X= 1 表示吃东西。

则有下列不等式:

m X+ X2+ X+...+ X k  ms

m X+ X3+ X+...+ Xk+1  k  ms

...

m Xn-k+1 + Xn-k+2+...+ X k  ms

我们令  Y k  m me ,则上述不等式可以转化为以下

的等式:

X+ X2+ X+...+ X+ Y= k  ms

X+ X3+ X+...+ Xk+1 + Y= k  ms

...

Xnk+1 + Xnk+2 +...+ X+Ynk+1 = k  ms

将这些等式两两相减,得:

X Xk+1 + Y1 Y2=0

X Xk+2 + Y2 Y3=0

...

Xn X+ Yn Ynk+1 = 0

(k  ms X X... X Y= 0

Xnk+1 + Xnk+2 +...+ X+Ynk+1  (k  ms) = 0

我们把等式左边加起来,发现恰好为0,满足流量平衡。

把上述每个等式看成一个点,若在第j个等式有-Yi,第k个等式有Yi,则向连一条从jk的容量为kmsme的边,若在第j个等式有-Xi,在第k个等式有Xi则连一条jk容量为1的边,然后对于正的常数c出现在第j个等式,从原点到j连一条容量为c的边,若对于负的常数-c出现在第k个等式,从k向汇点连一条容量为c的边,因为这一题还需要有费用,所以在相应的边上加上费用限制即可,最后跑一遍费用流。

Source

#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
         #include 
        
          #include 
         
           using namespace std; inline char read() { static const int IN_LEN = 1024 * 1024; static char buf[IN_LEN], *s, *t; if (s == t) { t = (s = buf) + fread(buf, 1, IN_LEN, stdin); if (s == t) return -1; } return *s++; } template 
          
            inline bool R(T &x) { static char c; static bool iosig; for (iosig = false, c = read(); !isdigit(c); c = read()) { if (c == -1) return false; if (c == '-') iosig = true; } for (x = 0; isdigit(c); c = read()) x = (x << 3) + (x << 1) + (c ^ '0'); if (iosig) x = -x; return true; } const int OUT_LEN = 1024 * 1024; char obuf[OUT_LEN], *oh = obuf; inline void writechar(char c) { if (oh == obuf + OUT_LEN) fwrite(obuf, 1, oh - obuf, stdout), oh = obuf; *oh++ = c; } template 
           
             inline void W(T x) { static int buf[30], cnt; if (!x) writechar(48); else { if (x < 0) writechar('-'), x = -x; for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48; while (cnt) writechar(buf[cnt--]); } } inline void flush() { fwrite(obuf, 1, oh - obuf, stdout); } const long long INF = 1e18; const int MAXN = 1000000 + 10; int s, t; long long ans1, sum, ans; long long dis[MAXN], f[MAXN]; bool vis[MAXN]; struct node { int to, rev; long long w, price; node(int to, long long w, long long price, int rev) : to(to), w(w), price(price), rev(rev) {} node() {} }; vector 
            
              edge[MAXN]; inline void create(int x, int y, long long w, long long c) { edge[x].push_back(node(y, w, c, edge[y].size())); if (x == y) edge[x].back().rev++; edge[y].push_back(node(x, 0, -c, edge[x].size() - 1)); } inline long long dfs(int cur, long long low, int t) { if (cur == t) return ans1 += low * sum, low; vis[cur] = true; int res = 0, delta; for (int p = 0; p < edge[cur].size(); ++p) { node &e = edge[cur][p]; if (e.w > 0 && !e.price && !vis[e.to]) { delta = dfs(e.to, min(low - res, e.w), t); if (delta) { e.w -= delta, edge[e.to][e.rev].w += delta, res += delta; if (res == low) break; } } } return res; } inline bool spfa_slf(int s, int t) { for (int i = s; i <= t; ++i) dis[i] = -INF; deque 
             
               q; dis[t] = 0, q.push_back(t); while (!q.empty()) { int j = q.front(); q.pop_front(); for (int p = 0; p < edge[j].size(); ++p) { node &e = edge[j][p]; if (edge[e.to][e.rev].w && dis[j] - e.price > dis[e.to]) { dis[e.to] = dis[j] - e.price; if (!q.empty() && dis[e.to] > dis[q.front()]) q.push_front(e.to); else q.push_back(e.to); } } } for (int i = s; i <= t; ++i) for (int p = 0; p < edge[i].size(); ++p) edge[i][p].price += dis[edge[i][p].to] - dis[i]; sum += dis[s]; return dis[s] > -INF; } inline void cost_flow(int s, int t) { while (spfa_slf(s, t)) do memset(vis, false, sizeof(vis)); while(dfs(s, INF, t)); } int n, k, ms, me; int ss[MAXN], ee[MAXN]; int main() { // freopen("in.in", "r", stdin); R(n), R(k), R(ms), R(me), me = k - me; for (int i = 1; i <= n; ++i) R(ss[i]); for (int i = 1; i <= n; ++i) R(ee[i]), ans += ee[i]; s = 0, t = n - k + 2 + 1; create(s, 1, me, 0); create(n - k + 2, t, me, 0); for (int i = 1; i <= n; ++i) { int u = max(1, i - k + 1), v = min(i + 1, n - k + 2); create(u, v, 1, ss[i] - ee[i]); } for (int i = 1; i <= n - k + 1; ++i) create(i, i + 1, me - ms, 0); cost_flow(s, t); W(ans1 + ans); flush(); return 0; } 
              
             
            
           
          
         
       
      
      
     
     
    
    
   
   

 

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值