给出一个长度为 n 的整数序列 hi ,现在要通过一些操作将这个序列修改为单调不降序列,即 hi≤hi+1 。
可以用的操作有 m 种,第 i 种操作可以通过支付 ci 的代价将一段长度恰为 li 的连续子序列 +1 或 ?1(由对应的操作符确定是 +1 还是 ?1 ,具体参考输入格式)。
不限制每种操作的使用次数,序列中的 hi 可以被改为任意整数(可以是负数),求最小代价,无解输出 ?1 。
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了刷题总结——怪题(ssoj费用流)相关的知识,希望对你有一定的参考价值。
给出一个长度为 n 的整数序列 hi ,现在要通过一些操作将这个序列修改为单调不降序列,即 hi≤hi+1 。
可以用的操作有 m 种,第 i 种操作可以通过支付 ci 的代价将一段长度恰为 li 的连续子序列 +1 或 ?1(由对应的操作符确定是 +1 还是 ?1 ,具体参考输入格式)。
不限制每种操作的使用次数,序列中的 hi 可以被改为任意整数(可以是负数),求最小代价,无解输出 ?1 。
第一行,两个整数 n,m 。
第二行,n 个整数 hi 。
接下来 m 行,每行格式为 opi,li,ci ,空格隔开,其中 opi 为一个字符,表示这种操作是 +1 还是 ?1 。
输出一行一个整数表示最小代价,若无解输出 -1 。
输入 [复制]
10 10
23 1 8 14 2 3 15 50 53 53
+ 4 6
- 1 10
+ 2 4
+ 4 2
- 3 5
+ 1 2
+ 3 2
+ 5 7
- 1 6
+ 4 5
输出
96
【数据规模】
对于 20% 的数据:n,m≤5;hi≤10;ci≤3 ;
对于另 20% 的数据:li=1;hi≤500 ;
对于 100% 的数据:n,m≤200;li≤n;1≤hi,ci≤106 。
其实这道题看数据范围外加分析是很容易猜出是费用流的·····难的是建图····
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<ctime> #include<cctype> #include<cstring> #include<string> #include<algorithm> #include<queue> using namespace std; const int N=205; const int M=400005; const int INF=0x3f3f3f3f; queue<int>que; int tot=1,first[N],next[M],go[M],rest[M],cost[M],S,T; int n,m,h[N],Tot,totflow,dis[N]; long long ans=0; bool visit[N],work[N]; char s[5]; inline int R() { char c;int f=0,i=1; for(c=getchar();(c<‘0‘||c>‘9‘)&&c!=‘-‘;c=getchar()); if(c==‘-‘) c=getchar(),i=-1; for(;c<=‘9‘&&c>=‘0‘;c=getchar()) f=(f<<3)+(f<<1)+c-‘0‘; return f*i; } inline void comb(int a,int b,int v,int w) { next[++tot]=first[a],first[a]=tot,go[tot]=b,rest[tot]=v,cost[tot]=w; next[++tot]=first[b],first[b]=tot,go[tot]=a,rest[tot]=0,cost[tot]=-w; } inline bool spfa() { memset(dis,INF,sizeof(dis));memset(work,false,sizeof(work));dis[S]=0; que.push(S); while(!que.empty()) { int u=que.front();que.pop();visit[u]=false; for(int e=first[u];e;e=next[e]) { int v=go[e]; if(dis[v]>dis[u]+cost[e]&&rest[e]>0) { dis[v]=dis[u]+cost[e]; if(!visit[v]) { visit[v]=true;que.push(v); } } } } return dis[T]!=INF; } inline int dinic(int u,int flow) { if(u==T) { ans+=(long long)dis[T]*flow; return flow; } int v,delta,res=0;work[u]=true; for(int e=first[u];e;e=next[e]) { if(dis[v=go[e]]==dis[u]+cost[e]&&rest[e]>0&&!work[v]) { delta=dinic(v,min(flow-res,rest[e])); if(delta) { res+=delta;rest[e]-=delta;rest[e^1]+=delta; if(res==flow) break; } } } return res; } inline void maxflow() { while(spfa()) totflow+=dinic(S,INF); } int main() { //freopen("a.in","r",stdin); n=R(),m=R();S=0,T=n+2; for(int i=1;i<=n;i++) { h[i]=R(); if(i==1) comb(S,i,INF,0); else { if(h[i]-h[i-1]>0) comb(S,i,h[i]-h[i-1],0); else if(h[i]-h[i-1]<0) comb(i,T,h[i-1]-h[i],0),Tot+=h[i-1]-h[i]; } } comb(S,n+1,INF,0);int l,c; while(m--) { scanf("%s",s);l=R(),c=R(); if(s[0]==‘+‘) for(int i=n+1;i-l>=1;i--) comb(i,i-l,INF,c); else for(int i=1;i+l<=n+1;i++) comb(i,i+l,INF,c); } maxflow(); if(totflow!=Tot) cout<<"-1"<<endl; else cout<<ans<<endl; return 0; }
以上是关于刷题总结——怪题(ssoj费用流)的主要内容,如果未能解决你的问题,请参考以下文章