【GDOI2017模拟8.20】准备食物2
来源:互联网 发布:mysql 修复数据表 编辑:程序博客网 时间:2024/04/28 07:52
Description
此生无悔入东方,来世愿生幻想乡! 我没入教,WorldWide_D(出题人)入了
古明地觉拥有的第三只眼,可以读取别人的内心想法,于是无论是妖怪,还是怨灵都为之感到恐惧,因此觉被人厌恶。
然而,觉却因能读心而深受那些无法开口的动物喜爱。整个地灵殿到处都是她的宠物(如火焰猫、地狱鸦)。
宠物多了,准备食物是个麻烦的问题。现在觉有m种食物,第i种食物有a[i]份。觉要为n个宠物按编号顺序分配食物,每个宠物需要1份食物。
觉通过读心,得出了每个宠物吃了每种食物后的喜悦值。觉还发现,对于一些宠物,假设它的编号为i,如果在它之前分配到食物的宠物中,超过s[i]个被分配了第num[i]种食物,那么它会密谋一些反动的事情(像间歇泉异变之类的)。
觉不允许反动的事情发生,也希望所有宠物获得的喜悦值最大,以让它们更好地为她管理地灵殿和灼热地狱的事务。现在她想知道,在不会反动的情况下,能获得的最大喜悦值为多少。如果无论怎样分配都会出现反动,或者食物不够分配,只要输出“Warning!”(不含引号)
1≤T≤5,1≤a[i],n≤200 1≤m≤100 -1≤s[i]≤n -1≤num[i]≤m且num[i]≠0 0≤v[i][j]≤100000
Solution
东方教徒真可怕.jpg
像这种一眼看过去有一堆奇奇怪怪的限制的,没有什么其他做法的题,当然是网络流啦!
显然最大费用最大流,无解最大流 < n。
所以我们只需要知道如何考虑限制。每个食物的总数也可以看成一个限制方便处理。
我们把限制食物相同的限制拉出来,按s排个序。
显然如果一个i,j(i < j),且si > sj那么限制i就是没有用的,扔掉。
现在我们就得到了一个递增的i和s都递增的限制,那么我们可以看成对一堆前缀进行限制。
显然相邻两个限制相当于限制一个区间最多选择的数量。
这样子我们就把限制划分成了许多不交的区间。
那么对于每一个限制的区间我们开一个点,从它所限制的点向它流容量为1,费用为v的边。然后这个点向这个食物所代表的点连容量为它的限制的边。
当然,因为区间直接相邻,我们也可以从上一个区间向它连上一个区间的限制。
最后一个区间向汇点连总限制。
这样就可以处理限制了。 忘记了zkw写最大费用最大流会出事啊
Code
#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define rep(i,a) for(int i=last[a];i;i=next[i])#define N 505#define M 51005using namespace std;const int inf=0x7fffffff,mx=200000;struct note{int s,num,id;}a[N];bool cmp(note x,note y) {return x.num<y.num||x.num==y.num&&x.s<y.s;}int ty,n,m,l,tot,S,T,id,ans,flow,value[N][N],dis[N],bz[N];int last[N],next[M],t[M],v[M],f[M];void add(int x,int y,int z,int c) { t[++l]=y;f[l]=z;v[l]=c;next[l]=last[x];last[x]=l; t[++l]=x;f[l]=0;v[l]=-c;next[l]=last[y];last[y]=l;}void link(int l,int r) { int p=0;bool pd=0;if (a[l].num<0) return; fo(i,l,r) { bool bz=0; fo(j,l,i-1) if (a[j].id>a[i].id) {bz=1;continue;} if (bz) continue;tot++; fo(j,a[p].id,a[i].id-1) add(j,tot,1,mx-value[j][a[l].num]); if (pd) add(tot-1,tot,a[p].s,0);p=i;pd=1; } if (pd) add(tot,T,a[p].s,0);}int aug(int x,int y,int z) { bz[x]=id; if (x==T) {ans+=y*z;flow+=y;return y;} rep(i,x) if (f[i]&&bz[t[i]]!=id&&dis[x]==dis[t[i]]+v[i]) { int k=aug(t[i],min(y,f[i]),z+v[i]); if (k) {f[i]-=k;f[i^1]+=k;return k;} } return 0;}bool find() { int k=inf; fo(i,S,tot) if (bz[i]==id) rep(j,i) if (bz[t[j]]!=id&&f[j]) k=min(k,dis[t[j]]-dis[i]+v[j]); if (k==inf) return 0; fo(i,S,tot) if (bz[i]==id) dis[i]+=k; return 1;}int main() { for(scanf("%d",&ty);ty;ty--) { l=1;memset(last,0,sizeof(last));S=id=ans=flow=0;T=tot=n+1; scanf("%d%d",&n,&m); fo(i,1,n) fo(j,1,m) scanf("%d",&value[i][j]); fo(i,1,n) scanf("%d%d",&a[i].s,&a[i].num),a[i].id=i; fo(i,1,m) scanf("%d",&a[i+n].s),a[i+n].num=i,a[i+n].id=n+1; sort(a+1,a+n+m+1,cmp); int la=1;a[0].id=1;fo(i,1,n) add(S,i,1,0); fo(i,1,n+m) if (a[i].num!=a[i-1].num) link(la,i-1),la=i; link(la,n+m); memset(dis,0,sizeof(dis));memset(bz,0,sizeof(bz)); do {id++;while (aug(S,inf,0)) id++;} while (find()); if (flow==n) printf("%d\n",n*mx-ans); else printf("Warning!\n"); }}
- 【GDOI2017模拟8.20】准备食物2
- jzoj 4718. 【GDOI2017模拟7.20】准备食物2 费用流
- JZOJ4718. 准备食物2
- [jzoj4598]【NOIP2016模拟7.9】准备食物
- 【JZOJ4718】准备食物2 题解
- 准备食物
- 准备食物
- 【JZOJ 4598】准备食物
- 【JZOJ 4598】 准备食物
- 【JZOJ4598】准备食物
- 【GDOI2017模拟7.17】两棵树
- 【GDOI2017模拟8.11】总结
- 【GDOI2017模拟8.12】躲藏
- 【GDOI2017模拟8.12】字符串
- 【GDOI2017模拟8.12】新车
- 【GDOI2017模拟8.11】选择
- 【GDOI2017模拟8.11】生物学家
- 【GDOI2017模拟8.15】Game
- 菜鸟的学习心得之为什么定义指针类型
- Sqlite 主键自动创建
- 图
- 基于dpdk协议栈的nginx,单core QPS达到28w
- 字符数组字符指针
- 【GDOI2017模拟8.20】准备食物2
- qduoj 求最大值
- C#委托变量Action和Func
- performSelector用法:
- Unity Shader Example 19 (fog)
- POJ - 1664 放苹果
- 使用三层交换机实现Vlan间互访
- 模板设计模式
- 3.32