2020上海大学校赛L 动物森友会(网络流+二分)

首先观察到答案具有单调性,可以二分答案判断。

至于判断方式,可以采用是否符合满流判断是否可以达到目的。

#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pll;
const int N=2e6+10;
const int M=2e6+10;
const int inf=0x3f3f3f3f;
int n,E;
ll h[N],ne[N],e[N];
ll f[N],idx;
int c[N];
int a[8][N],m;
ll sum;
int S,T;
int d[N],cur[N];
void add(int a,int b,int c){
    e[idx]=b,ne[idx]=h[a],f[idx]=c,h[a]=idx++;
    e[idx]=a,ne[idx]=h[b],f[idx]=0,h[b]=idx++;
}
int bfs(){
    memset(d,-1,sizeof d);
    d[S]=0;
    cur[S]=h[S];
    queue<int> q;
    q.push(S);
    while(q.size()){
        int t=q.front();
        q.pop();
        for(int i=h[t];i!=-1;i=ne[i]){
            int j=e[i];
            if(d[j]==-1&&f[i]){
                cur[j]=h[j];
                d[j]=d[t]+1;
                if(j==T)
                return true;
                q.push(j);
            }
        }
    }
    return false;
}
int find(int u,int limit){
    if(u==T){
        return limit;
    }
    int i;
    int flow=0;
    for(i=cur[u];i!=-1&&flow<limit;i=ne[i]){
        cur[u]=i;
        int j=e[i];
        if(d[j]==d[u]+1&&f[i]){
            int t=find(j,min(f[i],limit-flow));
            if(!t)
            d[j]=-1;
            else{
                f[i]-=t;
                f[i^1]+=t;
                flow+=t;
            }

        }
    }
    return flow;
}
int dinic(){
    int flow;
    int r=0;
    while(bfs()){
        while(flow=find(S,inf))
            r+=flow;
    }
    return r;
}
bool check(int x){
    S=0,T=7+n+1;
    idx=0;
    memset(h,-1,sizeof h);
    for (int i = 1; i <= 7; ++i){
        add(S,i,1ll*E*(x/7+(x%7>=i)));
    }
    for (int i=1;i<=n;++i) {
        for (int j=1;j<=7;++j){
            if(a[j][i])
                add(j,i+7,inf);
        }
        add(i+7,T,c[i]);
    }
    return dinic() >= sum;
}
signed main(){
    ios::sync_with_stdio(false);
    cin>>n>>E;
    memset(h,-1,sizeof h);
    int i;
    for(i=1;i<=n;i++){
        cin>>c[i]>>m;
        int j;
        sum+=c[i];
        for(j=1;j<=m;j++){
            int x;
            cin>>x;
            a[x][i]=1;
        }
    }
    int l=0,r=1e12;
    while(l<r){
        int mid=l+r>>1;
        if(check(mid)){
             r=mid;
        }
        else
            l=mid+1;
    }
    cout<<l<<endl;

}
View Code

 

posted @ 2020-09-09 21:26  朝暮不思  阅读(143)  评论(0编辑  收藏  举报