题意:
链接:https://ac.nowcoder.com/acm/contest/5278/L
来源:牛客网
Compute 最近开始玩动物森友会了。
这个游戏的时间与现实时间是同步的(一周有 7 天),而一些特定事件只会在一周的某些天解锁。
我们假设有 n 个不同的事件,而每个事件都会给予不同的材料,并且每个事件只会在一周中的特定几天开放,在开放的时间内可以完成多次。但由于 Compute 要参加训练,他每天并没有多少时间玩游戏,所以他每天最多只能完成 e 次事件。
现在 Compute 想做出一件非常稀有的道具——高达,并且他计算出了他收集齐所有材料需要完成每一种事件的次数。
假设现在 Compute 从周一开始玩这个游戏,他最少需要经过几天(包括不玩游戏的日子)才能造出高达?
题解:
/* *动物森友会 *题意: *一周有7天 *有n个不同的事件 *一个事件只会在一周中的特定几天开放 *在开放的时间可以完成多次 *每天最多完成e次 *每件事情有一个目标次数 *从周一开始玩,最少需要几天才能达到目标 *题解: *最小费用最大流的想法 *源点向所有事件连边,容量为目标次数 *所有事件向一周的7天连边,如果这个事件在当天能做 *容量为inf *一周中的所有天向汇点连边,容量为e*当天在天数中出现的次数 *二分天数 *天数上界是1e18 */ #include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=2e5+100; const ll inf=1e18; struct node { int u,v,nxt; ll w; }edge[maxn*2]; int head[maxn]; int tot; void addedge (int u,int v,ll w) { edge[tot].u=u; edge[tot].v=v; edge[tot].w=w; edge[tot].nxt=head[u]; head[u]=tot++; edge[tot].u=v; edge[tot].v=u; edge[tot].w=0; edge[tot].nxt=head[v]; head[v]=tot++; } int c[maxn]; int is[maxn][7];//事件i在第j天是否开放 int n,e; ll dep[maxn]; ll inq[maxn]; ll cur[maxn]; int wjm; ll maxflow=0; int s,t; bool bfs () { for (int i=0;i<=t;i++) { cur[i]=head[i]; dep[i]=inf; inq[i]=0; } dep[s]=0; queue<int> q; q.push(s); while (!q.empty()) { int u=q.front(); q.pop(); inq[u]=0; for (int i=head[u];i!=-1;i=edge[i].nxt) { int v=edge[i].v; if (dep[v]>dep[u]+1&&edge[i].w) { dep[v]=dep[u]+1; if (inq[v]==0) { q.push(v); inq[v]=1; } } } } if (dep[t]!=inf) return 1; return 0; } ll dfs (ll u,ll flow) { ll increase=0; if (u==t) { wjm=1; maxflow+=flow; return flow; } ll used=0; for (int i=cur[u];i!=-1;i=edge[i].nxt) { cur[u]=i; int v=edge[i].v; if (edge[i].w&&dep[v]==dep[u]+1) { if (increase=dfs(v,min(flow-used,edge[i].w))) { used+=increase; edge[i].w-=increase; edge[i^1].w+=increase; if (used==flow) break; } } } return used; } ll Dinic () { maxflow=0; while (bfs()) { wjm=1; while (wjm==1) { wjm=0; dfs(s,inf); } } return maxflow; } ll check (ll mid) { //mid表示天数 //0为源点 //1~n为事件点 //n+1~n+7表示天 //n+8表示汇点 for (int i=0;i<maxn;i++) head[i]=-1; tot=0; s=0; t=n+8; for (int i=1;i<=n;i++) addedge(s,i,c[i]); for (int i=1;i<=n;i++) { for (int j=1;j<=7;j++) { if (is[i][j]) { addedge(i,j+n,inf); } } } for (int i=1;i<=7;i++) addedge(i+n,t,(mid/7+(mid%7>=i))*e); ll ans=Dinic(); return ans; } int main () { scanf("%d%d",&n,&e); int sum=0; for (int i=1;i<=n;i++) { scanf("%d",c+i); sum+=c[i]; int m; scanf("%d",&m); for (int j=1;j<=m;j++) { int x; scanf("%d",&x); is[i][x]=1; } } ll l=1,r=1e9; ll u=-1; while (l<=r) { ll mid=(l+r)>>1; if (check(mid)==sum) { u=mid; r=mid-1; } else { l=mid+1; } } printf("%lld ",u); }