Nowcodercontest5278 L动物森友会(网络流)

cnblogs界面

只有7天,是不是可以直接贪心啊。。。

网络流做法:

二分答案天数为

建图:

源点向连边,第天的流量上限是

对于所有让,连上限为的边

每个向汇点连容量为

二分之后,判断是否满流即可

const int N=2e3+10,M=7*N,INF=1e9+10;

int n,m,S,T,vc;

//以下是网络流模板
struct Edge{
    int to,nxt,w;
}e[M<<1];
int head[N],ecnt;
void AddEdge(int u,int v,int w) {
    e[ecnt]=(Edge){v,head[u],w};
    head[u]=ecnt++;
}
void Link(int u,int v,int w){ AddEdge(u,v,w),AddEdge(v,u,0); }
#define erep(u,i) for(int i=head[u];~i;i=e[i].nxt)

int dis[N];
int Bfs(){
    static queue <int> que;
    rep(i,1,vc) dis[i]=INF;
    que.push(S),dis[S]=0;
    while(!que.empty()) {
        int u=que.front(); que.pop();
        erep(u,i) {
            int v=e[i].to,w=e[i].w;
            if(!w || dis[v]<=dis[u]+1) continue;
            dis[v]=dis[u]+1,que.push(v);
        }
    }
    return dis[T]<INF;
}

int Dfs(int u,int flowin) {
    if(u==T) return flowin;
    int flowout=0;
    erep(u,i) {
        int v=e[i].to,w=e[i].w;
        if(dis[v]!=dis[u]+1 || !w) continue;
        int t=Dfs(v,min(flowin-flowout,w));
        flowout+=t,e[i].w-=t,e[i^1].w+=t;
        if(flowin==flowout) break;
    }
    if(!flowout) dis[u]=0;
    return flowout;
}

int Dinic(){
    int ans=0;
    while(Bfs()) ans+=Dfs(S,INF);
    return ans;
}

int a[N][8],c[N],sum;

int Check(int mid) {
    if(m*mid<sum) return 0;
    rep(i,1,n+10) head[i]=-1; ecnt=vc=0;
    S=++vc,T=++vc;
    rep(i,1,7) Link(S,++vc,(mid/7+(mid%7>=i))*m);
    rep(i,1,n) {
        vc++;
        Link(vc,T,c[i]);
        rep(j,1,7) if(a[i][j]) Link(j+2,vc,INF);
    }
    return Dinic()==sum;
}


int main(){
    n=rd(),m=rd();
    rep(i,1,n) {
        c[i]=rd(),sum+=c[i];
        rep(j,1,rd()) a[i][rd()]=1;
    }
    // 二分答案,注意上界设定,防止边权爆int
    int l=0,r=1e9/m,res;
    while(l<=r) {
        int mid=(l+r)>>1;
        if(Check(mid)) r=mid-1,res=mid;
        else l=mid+1;
    }
    printf("%d\n",res);
}