zoukankan      html  css  js  c++  java
  • 【BZOJ 5222】[Lydsy2017省队十连测]怪题

    题目大意:

      传送门

      给一个长度为$n(n<=200)$的数列$h$,再给$m$个可以无限使用的操作,第$i$个操作为给长度为花费$c_i$的价值给长度为$l_i$的数列子序列+1或-1,求将数列变为不下降数列的最小花费。

    题解:

    第一部分(上下界最小费用可行流):  

      设$h_0=-inf,h_{n+1}=inf$,令$a$为$h$的差分数组,即$a_i=h_{i}-h_{i-1}$。考虑当对于区间$[l,r]$操作时(比如+1),相当于$a_{r+1}$减少1,$a_{l}$增加1。若将$a$数组看做点集,这个变化相当于从$r+1$到$l$的一条流量为$1$的有向边,反之(-1)亦然。

      显然问题相当于把$a$数组元素均变为 不为0。那么我们由S向$a_{i}>0$的位置连$flow=[0,a_{i}],cost=0$的边,表示${i}$可以减少流量上下界,对于$a_{i}<0$的位置,我们至少要使其增加$-a_i$所以我们向$T$连$flow=[-a_i,inf],cost=0$的边。对于每个操作我们由于可无限使用我们就给所有合法位置连$flow=[0,inf],cost=c_{i}$的边,然后我们可以跑一个上下界解决问题。

      等等,这样的确解决了问题,不过我们观察一下这个图,会发现上下界源点只连向了$T$,而上下界汇点只被那些$a_{i}<0$的点连接到。

      我们把这个图转化一下,会发现对于上面的建图方式,我们只把$a_{i}<0$的边建成$flow=-a_i,cost=0$的边即可,根本不需要跑上下界。这就是另外一种思考方式。

    第二部分(最小费用最大流):

      我们考虑那些$a_{i}<0$的点变为$0$一定比使其变为任一整数更优秀,同时这也是我们的判断有没有解的依据。

      所以我们就直接由$a_{i}<0$的点连向$T$的边为$flow=-a_i,cost=0$即可,如果所有连向$T$的边都流满,说明有解,同时由于上述性质,一定是最优解。

      

      不过这两个时间复杂度并没有太大区别。

    代码:

      1 #include "bits/stdc++.h"
      2 
      3 using namespace std;
      4 
      5 #define inf 0x3f3f3f3f
      6 
      7 inline int read() {
      8     int s=0,k=1;char ch=getchar ();
      9     while (ch<'0'|ch>'9') ch=='-'?k=-1:0,ch=getchar();
     10     while (ch>47&ch<='9') s=s*10+(ch^48),ch=getchar();
     11     return s*k;
     12 }
     13 
     14 const int N=1e3+10;
     15 
     16 struct edges {
     17     int v,cap,cost;edges *pair,*last;
     18 }edge[N*N],*head[N];int cnt;
     19 
     20 inline void push(int u,int v,int cap,int cost) {
     21     edge[++cnt]=(edges){v,cap,cost,edge+cnt+1,head[u]},head[u]=edge+cnt;
     22     edge[++cnt]=(edges){u,0,-cost,edge+cnt-1,head[v]},head[v]=edge+cnt;
     23 }
     24 
     25 int S,T,ss,tt,n,fl,m;
     26 int piS,vis[N];
     27 long long cost;
     28 
     29 inline int aug(int x,int w) {
     30     if (x==T) return cost+=1ll*piS*w,fl+=w,w;
     31     vis[x]=true;
     32     int ret=0;
     33     for (edges *i=head[x];i;i=i->last)
     34         if (i->cap&&!i->cost&&!vis[i->v])   {
     35             int flow=aug(i->v,min(i->cap,w));
     36             i->cap-=flow,i->pair->cap+=flow,ret+=flow,w-=flow;
     37             if (!w) break;
     38         }
     39     return ret;
     40 }
     41 
     42 inline bool modlabel() {
     43     static int d[N];
     44     memset(d,0x3f,sizeof d);d[T]=0;
     45     static deque<int> q;q.push_back(T);
     46     int dt;
     47     while (!q.empty()) {
     48         int x=q.front();q.pop_front();
     49         for (edges *i=head[x];i;i=i->last)  
     50             if (i->pair->cap&&(dt=d[x]-i->cost)<d[i->v])
     51                 (d[i->v]=dt)<=d[q.size()?q.front():0]
     52                     ?q.push_front(i->v):q.push_back(i->v);
     53     }
     54     for (int i=S;i<=T;++i)
     55         for (edges *j=head[i];j;j=j->last)
     56             j->cost+=d[j->v]-d[i];
     57     piS+=d[S];
     58     return d[S]<inf;
     59 }
     60 
     61 inline void solve() {
     62     piS = cost = 0;
     63     while(modlabel())
     64         do memset(vis,0,sizeof vis); 
     65     while(aug(S, inf));
     66 }
     67 
     68 int h[N],a[N],c[N],l[N],typ[N];
     69 int f[N],g[N];
     70 
     71 int main(){
     72     n=read(),m=read();
     73     for (int i=1;i<=n;++i)
     74         h[i]=read();
     75     for (int i=n;i>1;--i)
     76         h[i]=h[i]-h[i-1];
     77     h[1]=inf,h[n+1]=inf;
     78     ss=n+2,tt=ss+1,T=tt+1;
     79     char opt[2];
     80     for (int i=1;i<=m;++i) {
     81         scanf("%s",opt),l[i]=read(),c[i]=read();
     82         typ[i]=opt[0]=='+';
     83     }
     84     ++n;
     85     for (int i=1;i<=n;++i)
     86         if (h[i] > 0)
     87             push(ss,i,h[i],0);
     88         else if(h[i]<0)  push(i,tt,inf,0),a[i]=-h[i],a[tt]+=h[i],push(i,T,a[i],0);
     89     push(tt,ss,inf,0);
     90     push(S,tt,-a[tt],0);
     91     memset(f,0x3f,sizeof(f));
     92     f[0]=0;
     93     memcpy(g,f,sizeof g);
     94     for (int j=1;j<=m;++j)  
     95         for (int k=l[j];k<=n;k+=l[j])
     96             if(typ[j])  
     97                 for (int i=n-1;i>=l[j];--i)
     98                     f[i]=min(f[i],f[i-l[j]]+c[j]);
     99             else 
    100                 for (int i=n-1;i>=l[j];--i)
    101                     g[i]=min(g[i],g[i-l[j]]+c[j]);
    102     // puts()
    103     for (int j=1;j<=m;++j)  
    104         if (typ[j]){
    105             if (f[l[j]]==c[j])  
    106                 for (int i=l[j]+1;i<=n;++i)
    107                     push(i,i-l[j],inf,c[j]);
    108         }else 
    109             if (g[l[j]]==c[j])
    110                 for (int i=1;i+l[j]<=n;++i)
    111                     push(i,i+l[j],inf,c[j]); 
    112     solve();
    113     if (fl==-a[tt])
    114         printf("%lld
    ",cost);
    115     else puts("-1");
    116 }
    上下界
      1 #include "bits/stdc++.h"
      2 
      3 using namespace std;
      4 
      5 #define inf 0x3f3f3f3f
      6 
      7 inline int read() {
      8     int s=0,k=1;char ch=getchar ();
      9     while (ch<'0'|ch>'9') ch=='-'?k=-1:0,ch=getchar();
     10     while (ch>47&ch<='9') s=s*10+(ch^48),ch=getchar();
     11     return s*k;
     12 }
     13 
     14 const int N=1e3+10;
     15 
     16 struct edges {
     17     int v,cap,cost;edges *pair,*last;
     18 }edge[N*N],*head[N];int cnt;
     19 
     20 inline void push(int u,int v,int cap,int cost) {
     21     edge[++cnt]=(edges){v,cap,cost,edge+cnt+1,head[u]},head[u]=edge+cnt;
     22     edge[++cnt]=(edges){u,0,-cost,edge+cnt-1,head[v]},head[v]=edge+cnt;
     23 }
     24 
     25 int S,T,ss,tt,n,fl,m;
     26 int piS,vis[N];
     27 long long cost;
     28 
     29 inline int aug(int x,int w) {
     30     if (x==T) return cost+=1ll*piS*w,fl+=w,w;
     31     vis[x]=true;
     32     int ret=0;
     33     for (edges *i=head[x];i;i=i->last)
     34         if (i->cap&&!i->cost&&!vis[i->v])   {
     35             int flow=aug(i->v,min(i->cap,w));
     36             i->cap-=flow,i->pair->cap+=flow,ret+=flow,w-=flow;
     37             if (!w) break;
     38         }
     39     return ret;
     40 }
     41 
     42 inline bool modlabel() {
     43     static int d[N];
     44     memset(d,0x3f,sizeof d);d[T]=0;
     45     static deque<int> q;q.push_back(T);
     46     int dt;
     47     while (!q.empty()) {
     48         int x=q.front();q.pop_front();
     49         for (edges *i=head[x];i;i=i->last)  
     50             if (i->pair->cap&&(dt=d[x]-i->cost)<d[i->v])
     51                 (d[i->v]=dt)<=d[q.size()?q.front():0]
     52                     ?q.push_front(i->v):q.push_back(i->v);
     53     }
     54     for (int i=S;i<=T;++i)
     55         for (edges *j=head[i];j;j=j->last)
     56             j->cost+=d[j->v]-d[i];
     57     piS+=d[S];
     58     return d[S]<inf;
     59 }
     60 
     61 inline void solve() {
     62     piS = cost = 0;
     63     while(modlabel())
     64         do memset(vis,0,sizeof vis); 
     65     while(aug(S, inf));
     66 }
     67 
     68 int h[N],a[N],c[N],l[N],typ[N];
     69 int f[N],g[N];
     70 
     71 int main(){
     72     n=read(),m=read();
     73     for (int i=1;i<=n;++i)
     74         h[i]=read();
     75     for (int i=n;i>1;--i)
     76         h[i]=h[i]-h[i-1];
     77     h[1]=inf,h[n+1]=inf;
     78     // ss=n+2,tt=ss+1,T=tt+1;
     79     char opt[2];
     80     for (int i=1;i<=m;++i) {
     81         scanf("%s",opt),l[i]=read(),c[i]=read();
     82         typ[i]=opt[0]=='+';
     83     }
     84     ++n;T=n+1;
     85     for (int i=1;i<=n;++i)
     86         if (h[i] > 0)
     87             push(S,i,h[i],0);
     88         else if(h[i]<0)  push(i,T,-h[i],0),a[tt]+=h[i];//,push(i,T,a[i],0);
     89     // push(tt,ss,inf,0);
     90     // push(S,tt,-a[tt],0);
     91     memset(f,0x3f,sizeof(f));
     92     f[0]=0;
     93     memcpy(g,f,sizeof g);
     94     for (int j=1;j<=m;++j)  
     95         for (int k=l[j];k<=n;k+=l[j])
     96             if(typ[j])  
     97                 for (int i=n-1;i>=l[j];--i)
     98                     f[i]=min(f[i],f[i-l[j]]+c[j]);
     99             else 
    100                 for (int i=n-1;i>=l[j];--i)
    101                     g[i]=min(g[i],g[i-l[j]]+c[j]);
    102     for (int j=1;j<=m;++j)  
    103         if (typ[j]){
    104             if (f[l[j]]==c[j])  
    105                 for (int i=l[j]+1;i<=n;++i)
    106                     push(i,i-l[j],inf,c[j]);
    107         }else 
    108             if (g[l[j]]==c[j])
    109                 for (int i=1;i+l[j]<=n;++i)
    110                     push(i,i+l[j],inf,c[j]); 
    111     solve();
    112     // printf("%d %d
    ",fl);
    113     if (fl==-a[tt])
    114         printf("%lld
    ",cost);
    115     else puts("-1");
    116 }
    最大流
  • 相关阅读:
    【资源集合】知识学习途径
    【经验总结】vue + element-ui 踩坑—— table 篇
    quartz和crontab的区别
    pycharm自动生成文件注释和函数注释
    IDEA设置类注解和方法注解(详解)
    kali linux 中科大 source
    kali中签名出错
    GTK+入门教程
    GTK hello player
    libgtk Gtk 窗口,控件,设置(添加图片等)
  • 原文地址:https://www.cnblogs.com/Troywar/p/8847678.html
Copyright © 2011-2022 走看看