bzoj4842: [Neerc2016]Delight for a Cat

bzoj4842

这是一道网络流的题(大家都看出来了吧)

 首先我们简化一下题目,选出最关键的部分(就是知道什么和要求什么,还有条件

我们在这里把睡觉设为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    
代码
原文地址:https://www.cnblogs.com/cylyz/p/10598022.html