【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\n",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\n",fl); 113 if (fl==-a[tt]) 114 printf("%lld\n",cost); 115 else puts("-1"); 116 }最大流
【BZOJ 5222】[Lydsy2017省隊十連測]怪題