bzoj4842: [Neerc2016]Delight for a Cat
作者:互联网
https://www.lydsy.com/JudgeOnline/problem.php?id=4842
这是一道网络流的题(大家都看出来了吧)
首先我们简化一下题目,选出最关键的部分(就是知道什么和要求什么,还有条件)
我们在这里把睡觉设为0,至少有t0时间在睡觉,把打隔膜设为1,至少t2时间在打隔膜(方便下面描述)
这样的话就转换成了一个序列问题 ,数列上的点可以选为0或1,第i个位置选0有si的收益,选1有ei的收益,长度为k的序列里至少有t0个0和t1个1。求如何填数才能令这个序列达的收益最大,输出最大收益和填数方案。
样例就不用解释了吧,大家都懂。
假设所有点都选了0,操作由赋值0或1改为将哪些0变为1后更优,每一个0变为1后都有ei-si的收益,一个长度为k的区间内至少有t1个1,定为下界L=t1,至多有k-t0个1(至少有t0个0)定为上界U,(是有上下界的网络流的题!!不过正解不是那样)这样变换后可以试操作更简单。
既然是网络流的,我们考虑怎么建图,一看是一个序列,先把序列上的点依次连接起来S连向1,n连向T,中间的i连向i+1;
然后步入正题,看看本题应该怎么做,参考一下下图:
先只考虑有上界的问题
对于每个点i,我们将它像i+k号点连一条边,表示选了这个点(0改为1),将这一点的流量分走,分向下一个区间,剩下的流量就 -1 表示这个区间内能改的点的个数-1。
将S流向1 的边流量设定为上界U,这样可以保证每个k区间的流量都<=上界。这样就能控制住每个区间内最多分出去U的流量,就是说最多选上界个点;
再考虑下界,就是最少选L个1;也就是说要让这个区间内最少流出L的流量,那么剩下的流量最多就只能流U-L了。所以我们把每个区间末尾的那个边的流量定为U-L控制最多剩下多少流量。
(大家用各种优美姿势感性理解一下)
还有注意不要全开long long ;
不开long long会爆int ,全开会超时~~~这个东西卡了我一个小时。。
至于怎么输出方案,大家胡乱搞一下就好了。
1 #include<iostream> 2 #include<queue> 3 #include<bit/stdc++.h> 4 using namespace std; 5 #define LL long long 6 #define C continue 7 #define B break 8 #define MAXN 101000 9 #define inf 100000007 10 inline LL read() 11 { 12 LL x=0,f=1; 13 char ch=getchar(); 14 while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} 15 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} 16 return x*f; 17 } 18 int n,k,t0,t1,S,T,lin[MAXN],t=1; 19 int v[MAXN],pre[MAXN],U,L,id[MAXN],S0; 20 LL aa,d[MAXN],AKAKAKAK[MAXN],a[MAXN],ans=0,sum; 21 int incf[MAXN]; 22 struct adge{ 23 int y,ne,c,v; 24 }e[2*MAXN]; 25 void insert(int xx,int yy,int cc,int vv) 26 { 27 e[++t].y=yy;e[t].v=vv;e[t].c=cc;e[t].ne=lin[xx];lin[xx]=t; 28 e[++t].y=xx;e[t].v=-vv;e[t].c=0;e[t].ne=lin[yy];lin[yy]=t; 29 }queue<int> q; 30 bool SP_spfa(int st) 31 { 32 while(q.size())q.pop(); 33 memset(d,127,sizeof(d)); 34 aa=d[1]; 35 memset(v,0,sizeof(v)); 36 q.push(st),d[st]=0,v[st]=1; 37 incf[st]=(1<<30); 38 while(q.size()) 39 { 40 int x=q.front(); 41 q.pop(); 42 v[x]=0; 43 for(int i=lin[x];i;i=e[i].ne) 44 { 45 int y=e[i].y; 46 if(d[y]>d[x]+e[i].v&&e[i].c) 47 { 48 d[y]=d[x]+e[i].v; 49 incf[y]=min(incf[x],e[i].c); 50 pre[y]=i; 51 if(!v[y]) 52 { 53 v[y]=1; 54 q.push(y); 55 } 56 } 57 } 58 } 59 if(d[T]==aa) return 0; 60 return 1; 61 } 62 void Update() 63 { 64 int x=T; 65 while(x!=S) 66 { 67 int i=pre[x]; 68 e[i].c-=incf[T]; 69 e[i^1].c+=incf[T]; 70 x=e[i^1].y; 71 } 72 ans+=(LL)d[T]*incf[T]; 73 } 74 int main() 75 { 76 //freopen("www.in","r",stdin); 77 //freopen("www.out","w",stdout); 78 n=read(),k=read(),t0=read(),t1=read(); 79 for(int i=1;i<=n;++i) AKAKAKAK[i]=read(),sum+=AKAKAKAK[i]; 80 for(int i=1;i<=n;++i) a[i]=read()-AKAKAKAK[i]; 81 S=0,T=n+1;U=k-t0;L=t1;S0=n+2; 82 insert(S,S0,U,0); 83 for(int i=1;i<=n;++i) 84 { 85 /*insert(i,min(i+k,T),1,-a[i]); 86 if(i<k) insert(i,i+1,inf,0); 87 else insert(i,i+1,U-L,0);*/ 88 if(i<=k) insert(S0,i,inf,0); 89 insert(i,min(i+1,T),U-L,0); 90 insert(i,min(i+k,T),1,-a[i]); 91 id[i]=t; 92 } 93 while(SP_spfa(S))Update(); 94 cout<<sum-ans<<endl; 95 for(int i=1;i<=n;++i) { 96 if(e[id[i]^1].c) putchar('S'); 97 else putchar('E'); 98 } 99 //cout<<s<<endl; 100 return 0; 101 } 102代码
标签:int,bzoj4842,long,Delight,read,t0,incf,Neerc2016,define 来源: https://www.cnblogs.com/cylyz/p/10598022.html