洛谷题目传送门

说不定比官方sol里的某理论最优算法还优秀一点?

所以\(n,m\)说不定可以出到\(1000\)?

无所谓啦,反正是个得分题。Orz良心出题人,暴力有70分2333

思路分析

正解的思路很巧妙,其实我并不觉得这是个正儿八经的网络流或者二分图匹配的题目,主要还是个思维+建图模型+乱搞。。。。。。

\(C=1\)时我们就可以对于每个人直接匹配而不会影响到后面的选择了。但是\(C>1\)的话,可能某一个人可以选多个导师,当他随便选了其中一个以后,可能影响到后面某个人使其选不到本来的最优解。而此时后面那个人就要让前面那个人改变决策,做出反悔。

这时候有没有想到网络流算法的反悔边的应用呢?(因为蒟蒻只会网络流所以就用网络流来跑二分图匹配)建一个二分图,左边\(n\)个点代表选手,右边\(m\)个点代表导师(战队),一开始所有导师向汇点\(T\)连流量为战队人数上限的边。每次从前往后枚举选手,找到能够选择的最高志愿,动态地向该档志愿能选择的所有导师连容量为\(1\)的边,然后增广一次(这时会随意选择一个可行的导师)。因为增广后会留下反悔边,所以这样做就很方便啦。因为每次是动态加边直接从每个选手开始增广 ,所以貌似连源点都不需要(这就是蒟蒻一直觉得这题像一个乱搞题的原因)

这时候留下一个问题,如何方便地判断某时刻某战队是否已经不可选了呢?暴力存图实在是太麻烦啦!而且我们并不需要知道整个图是什么样子,只要知道这一些bool型状态,暴力存图实在是浪费时空。大概算法复杂度优化的瓶颈就在这里吧。一开始蒟蒻yy各种极其错误的方法来乱搞。后来发现,将问题带入到我们建的网络流模型里面,不就是要知道每个代表导师的点到汇点是否存在增广路吗?具体方法,从汇点开始dfs搜索,如果某条边的反向边有流量就搜过去,把搜到的点标记起来就好啦!

对于第二问,显然可以想到二分。先把每次每个战队能否选择的状态保存下来,对于每个选手,二分他之前的排名,根据是否存在一个可以选择而且令他满意的战队来决定下面往哪一半区间接着找。

复杂度分析

有三步。首先要暴力找到能满足的最高志愿,复杂度\(O(nm)\)

接着,增广(蒟蒻直接dfs去找而不是dinic)和更新当前战队是否可选状态,因为是在图上搞,边数不超过\(O(nC)\),所以这部分的复杂度都是\(O(n^2C)\)的(据说在二分图上使用dinic可以使增广的复杂度降到\(O(n\sqrt nC)\)?但是这是动态加边,每次都要跑,那应该是不能优化的吧)

最后,二分最少上升的排名,复杂度\(O(nm\log n)\)

综上,因为n与m同阶,所以总复杂度应该是\(O(n^2(C+\log n))\)级别的。由于是网络流,所以复杂度非常玄学,也不至于删边那么麻烦,蒟蒻随意加了一点点剪枝,还有register,inline,快读快写,就只要8ms,开O2 4ms。居然没有0msTAT,欢迎超越

最后提一个惨痛的经历:蒟蒻调这题一天多了,所有的算法性错误都更正了,还是WA,最后才发现重建图的时候反向边的流量忘记赋成0来覆盖掉原来的信息了TAT

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<cstring>
  4. #define R register int
  5. #define I inline void
  6. #define pc(C) *po++=C
  7. #define add(X,Y,F)\
  8. to[++p]=Y,ne[p]=he[X],f[he[X]=p]=F,\
  9. to[++p]=X,ne[p]=he[Y],f[he[Y]=p]=0//反边赋0!
  10. const int SZ=1<<20,N=209,M=N<<1,L=N*22;//边数最多2(nC+m)
  11. char ibuf[SZ],obuf[SZ],*pi=ibuf-1,*po=obuf;
  12. I in(R&x){
  13. while(*++pi<'-');
  14. x=*pi&15;
  15. while(*++pi>'-')x*=10,x+=*pi&15;
  16. }
  17. I out(R x){
  18. if(x>9)out(x/10);
  19. pc(x%10|'0');
  20. }
  21. int T,he[M],ne[L],to[L],f[L],he1[N],ne1[N];
  22. int a[N][N],b[N],up[N];//up记录最少上升排名
  23. bool c[N][N],vis[M];//c存下战队是否可选
  24. void remain(R x){//更新状态,利用好反向边!
  25. vis[x]=1;
  26. for(R i=he[x];i;i=ne[i])
  27. if(f[i^1]&&!vis[to[i]])remain(to[i]);
  28. }
  29. bool flow(R x){//dfs增广
  30. if(vis[x])return x==T;
  31. vis[x]=1;
  32. for(R i=he[x];i;i=ne[i])
  33. if(f[i]&&flow(to[i])){
  34. --f[i];++f[i^1];
  35. return 1;
  36. }
  37. return 0;
  38. }
  39. int main(){
  40. fread(ibuf,1,SZ,stdin);
  41. R TT,CC,n,m,p,i,j,x,s,l,r,mi;
  42. in(TT);in(CC);
  43. while(TT--){
  44. in(n);in(m);
  45. T=n+m+1;p=vis[T]=1;
  46. for(j=1;j<=m;++j)
  47. in(b[j]),add(j+n,T,b[j]);
  48. for(i=1;i<=n;++i)
  49. for(j=1;j<=m;++j)in(a[i][j]);
  50. for(j=1;j<=m;++j)
  51. c[1][j]=(bool)b[j];//初始状态就是收不收人(不会来个导师不收人吧233)
  52. for(i=1;i<=n;++i){
  53. memset(he1,0,(n+1)<<2);
  54. for(j=1;j<=m;++j)//链表把同等级志愿挂一起,像邻接表一样
  55. ne1[j]=he1[a[i][j]],he1[a[i][j]]=j;
  56. for(x=1;x<=m;++x){
  57. for(j=he1[x];j;j=ne1[j])
  58. if(c[i][j])break;
  59. if(j){
  60. for(j=he1[x];j;j=ne1[j])
  61. if(c[i][j])add(i,j+n,1);//贪心选择,动态连边
  62. memset(vis,0,T);flow(i);
  63. break;
  64. }
  65. }
  66. out(x);pc(' ');
  67. if(x<=m){
  68. memset(vis,0,T);remain(T);
  69. memcpy(c[i+1]+1,vis+n+1,m);
  70. }//没选到肯定状态不变啦,直接copy上一次的
  71. else memcpy(c[i+1]+1,c[i]+1,N);
  72. in(s);if(x<=s){up[i]=0;continue;}//判掉一开始就满意的
  73. l=0;r=i-1;
  74. F:while(l!=r){
  75. mi=(l+r+1)>>1;//注意二分区间是左闭右开的,所以要写成这样
  76. for(x=s;x;--x)
  77. for(j=he1[x];j;j=ne1[j])
  78. if(c[mi][j]){l=mi;goto F;}
  79. r=mi-1;
  80. }
  81. up[i]=i-l;
  82. }
  83. pc('\n');for(i=1;i<=n;++i){out(up[i]);pc(' ');}pc('\n');
  84. memset(he,0,(T+1)<<2);//应该只有he需要清空
  85. }
  86. fwrite(obuf,1,po-obuf,stdout);
  87. return 0;
  88. }

洛谷P4382 [八省联考2018]劈配(网络流,二分答案)的更多相关文章

  1. P4382 [八省联考2018]劈配

    题目链接 题意分析 受到了\(olinr\ \ julao\)的影响 写了匈牙利算法 首先 我们对于每一个人 从高到低枚举志愿 如果当前志愿的老师有剩余的话 那么我们就选 否则的话 我们看看谁的那个志 ...

  2. BZOJ.5251.[八省联考2018]劈配mentor(最大流)

    BZOJ 洛谷 对于每个人,每次枚举一个志愿看是否能增广即可. 对于第二问,可以保留第一问中\(n\)次增广前后的\(n\)张图,二分,在对应图上看是否能增广即可. 貌似匈牙利的某种写法比网络流优多了 ...

  3. [BZOJ5251][九省联考2018]劈配(网络流)

    5251: [2018多省省队联测]劈配 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 33  Solved: 22[Submit][Status][ ...

  4. 洛谷P4383 [八省联考2018]林克卡特树lct(DP凸优化/wqs二分)

    题目描述 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的迷你挑战. 游戏中有一个叫做“LCT” 的挑 ...

  5. 洛谷 4383 [八省联考2018]林克卡特树lct——树形DP+带权二分

    题目:https://www.luogu.org/problemnew/show/P4383 关于带权二分:https://www.cnblogs.com/flashhu/p/9480669.html ...

  6. 洛谷.4383.[八省联考2018]林克卡特树lct(树形DP 带权二分)

    题目链接 \(Description\) 给定一棵边带权的树.求删掉K条边.再连上K条权为0的边后,新树的最大直径. \(n,K\leq3\times10^5\). \(Solution\) 题目可以 ...

  7. dp凸优化/wqs二分学习笔记(洛谷4383 [八省联考2018]林克卡特树lct)

    qwq 安利一个凸优化讲的比较好的博客 https://www.cnblogs.com/Gloid/p/9433783.html 但是他的暴力部分略微有点问题 qwq 我还是详细的讲一下这个题+这个知 ...

  8. [八省联考2018] 劈配 mentor

    Description 一年一度的综艺节目<中国新代码>又开始了.Zayid 从小就梦想成为一名程序员,他觉得这是一个展示自己的舞台,于是他毫不犹豫地报名了. Input 轻车熟路的Zay ...

  9. BZOJ5251 八省联考2018劈配(网络流)

    劈配,匹配,网络流.那么考虑怎么跑网络流. 先看第一问.首先套路的建出超源超汇.不用想也知道导师向汇连容量为战队人数上限的边.特别地,给出局也建一个点,向汇连容量inf的边(似乎没有必要).对于一个新 ...

随机推荐

  1. ASP.NET Core MVC中的IActionFilter.OnActionExecuting方法,可以获取Controller的Action方法参数值

    用过ASP.NET Core MVC中IActionFilter拦截器的开发人员,都知道这是一个非常强大的MVC拦截器.最近才发现IActionFilter的OnActionExecuting方法,甚 ...

  2. UWP 下载文件显示下载进度

    <Page x:Class="WgscdProject.TestDownloadPage" xmlns="http://schemas.microsoft.com/ ...

  3. mfc 控件添加变量

    关联控件变量 初始化数据 一.关联控件变量 .为Edit控件关联数值类变量 变量名 m_edt1_s .为Edit控件关联控件类变量 变量名 m_edt1_ctl 二.控件变量的使用 HWND h=: ...

  4. 11.7 (下午)开课二个月零三天 (PDO)

    PDO访问方式操作数据库   mysqli是专门访问MySQL数据库的,不能访问其它数据库.PDO可以访问多种的数据库,它把操作类合并在一起,做成一个数据访问抽象层,这个抽象层就是PDO,根据类操作对 ...

  5. async await使用

    promise使用 var sleep = function (time) { return new Promise(function (resolve, reject) { setTimeout(f ...

  6. SSISDB5:使用TSQL脚本执行Package

    SSISDB 系列随笔汇总: SSISDB1:使用SSISDB管理Package SSISDB2:SSIS工程的操作实例 SSISDB3:Package的执行实例 SSISDB4:当前正在运行的Pac ...

  7. java File读取文件始终不存在的问题分析

    先上图: 如图,f1 始终能读到该文件,使用的是绝对路径 f2 却是相对路径. 感觉很奇怪,明明一模一样的代码为什么会产生不同的结果呢? 首先想到的是是不是有什么特殊字符.. 拿到notepad++中 ...

  8. effective c++ 笔记 (49-52)

    //---------------------------15/04/27---------------------------- //#49   了解new-handler的行为 { /* 1:在o ...

  9. 用Unity简单实现第三人称人物的移动和转向

    上图不重要,因为实现人物的移动用的是动画,没有什么可说的,主要是下面实现人物的转向. 比如在一个平面中,玩家按了w和d键则人物会面向右前方向前进,如果此时玩家按了a和s键则人物会面向左后方向前进,那么 ...

  10. 【Beta阶段】启程会议——第零次Scrum Meeting!

    本次会议为Beta阶段功能的概括性介绍与任务主线的确定会议. 本次会议拟确定第二阶段各位队员的内容与主要职责 会议时长:1小时30分(因为是启程会议,所以说的比较多) 会议地点:7公寓1楼会客室   ...