这题目写了我好长时间,但还是几乎(不要在意细节)一遍 A 了喵~

据说有代码奇短的,Orz 思路巧妙的大爷

想我这种 Brute Force 写写的傻 X 真是代码量飞起来了耶,喵~

如果把每个人看成点,每个人要 kill 的人向此人连出一条有向边,那么每个点仅有一条出边和一条入边

经验告诉我们,这就是 环+内向图 的节奏

经验又告诉我,处理这种图要么先暴力搞环,再搞挂在环上的树。要么先搞树,再弄环。

此题显然是后者

环+内向图只需要用 bfs 就可以搞出来了,看到写 tarjan 的真是 Orz

弄出 环 和 树 后,先在树上跑 dp,用 dp[u][0] 表示如果 u 最后被 kill 了,那么以 u 为根子树最少要死几人, dp[u][1] 是 u 存活下来的情况

这是普及组难度的树形 dp 吧喵~

再在环上跑 dp ,我们先破环为链,则有3种情况 (我们令在首的人为 A , 在尾的人为 B)

1. A君 最后活着,那 B君 一定被 kill 了

2. A君 最后被 kill 了,B君 存活了或也被 kill 了

3. A君 存活了下来,B君 也存活了下来,然后 B君 kill A君

三种情况要分类讨论

中间过程的状态转移和以上三种情况类似,无非就是讨论 i 君 和 i+1 君 的是否被 kill 的关系  (妈妈说,某个字打出来是不好的喵~)

被 kill 有两种可能:1.被自己的子树中的某君 kill 了  2.被环上的某君 kill 了

这个 dp 也很好想嘛

似乎除了难写就没有难度了喵?

  1. #include <cstdio>
  2. #include <cstring>
  3. const int size=;
  4. const int inf=size;
  5.  
  6. namespace IOspace
  7. {
  8. inline void assign() {freopen("isaac.in", "r", stdin); freopen("isaac.out", "w", stdout);}
  9. inline void close() {fclose(stdin); fclose(stdout);}
  10. inline int getint()
  11. {
  12. register int num=;
  13. register char ch;
  14. do ch=getchar(); while (ch<'' || ch>'');
  15. do num=num*+ch-'', ch=getchar(); while (ch>='' && ch<='');
  16. return num;
  17. }
  18. inline void putint(int num, char ch='\n')
  19. {
  20. char stack[];
  21. register int top=;
  22. if (num==) stack[top=]='';
  23. for ( ;num;num/=) stack[++top]=num%+'';
  24. for ( ;top;top--) putchar(stack[top]);
  25. if (ch) putchar(ch);
  26. }
  27. }
  28.  
  29. int n;
  30. int g[size][];
  31. int t, a[size];
  32. int f[size], d[size];
  33. int dp[size][];
  34. bool vis[size], loop[size];
  35.  
  36. struct edge {int point; edge * next;};
  37. edge MEM[size], * PORT=MEM;
  38. edge * E[size];
  39. inline edge * newedge(int _point, edge * _next)
  40. {edge * ret=PORT++; ret->point=_point; ret->next=_next; return ret;}
  41.  
  42. inline int min(int x, int y) {return x<y?x:y;}
  43. inline int max(int x, int y) {return x>y?x:y;}
  44. inline void add(int & x, int y) {if (x>=inf || y>=inf) x=inf; else x+=y;}
  45. inline int search(int);
  46. inline int find(int);
  47. inline void bfs(int);
  48.  
  49. int main()
  50. {
  51. int ans1=, ans2=;
  52.  
  53. n=IOspace::getint();
  54. for (int i=;i<=n;i++)
  55. {
  56. f[i]=IOspace::getint(), d[f[i]]++;
  57. if (f[i]==i) ans2++, vis[i]=;
  58. E[f[i]]=newedge(i, E[f[i]]);
  59. }
  60.  
  61. for (int i=;i<=n;i++) if (!d[i])
  62. {
  63. vis[i]=;
  64. ans2+=search(i);
  65. }
  66. for (int i=;i<=n;i++) if (!vis[i])
  67. {
  68. vis[i]=;
  69. ans2+=search(i);
  70. }
  71.  
  72. memset(vis, , sizeof(vis));
  73. for (int i=;i<=n;i++) if (!vis[i])
  74. {
  75. vis[i]=;
  76. ans1+=find(i);
  77. }
  78.  
  79. IOspace::putint(ans1, ' '); IOspace::putint(ans2);
  80.  
  81. return ;
  82. }
  83. inline int search(int x)
  84. {
  85. int ret=;
  86. for (x=f[x];!vis[x];x=f[x]) vis[x]=, ret++;
  87. return ret;
  88. }
  89. inline void bfs(int x)
  90. {
  91. static int l, r, q[size];
  92.  
  93. l=r=;
  94. for (q[r++]=x;l<r; )
  95. {
  96. int u=q[l++];
  97. for (edge * i=E[u];i;i=i->next)
  98. if (!loop[i->point])
  99. {
  100. vis[i->point]=;
  101. q[r++]=i->point;
  102. }
  103. }
  104.  
  105. for (int i=r-;i>=;i--)
  106. if (E[q[i]]==NULL) dp[q[i]][]=inf;
  107. else if (E[q[i]]->next==NULL && loop[E[q[i]]->point]) dp[q[i]][]=((E[q[i]]->point)==q[i])?:inf;
  108. else
  109. {
  110. for (edge * j=E[q[i]];j;j=j->next)
  111. if (!loop[j->point])
  112. add(dp[q[i]][], dp[j->point][]);
  113. for (edge * j=E[q[i]];j;j=j->next)
  114. if (!loop[j->point])
  115. add(dp[q[i]][], min(dp[j->point][], dp[j->point][]));
  116. add(dp[q[i]][], );
  117. }
  118. }
  119. inline int find(int x)
  120. {
  121. int ret=;
  122.  
  123. vis[x]=;
  124. for (x=f[x];!vis[x];x=f[x]) vis[x]=;
  125. for (t=;!loop[x];x=f[x]) loop[a[t++]=x]=;
  126. for (int i=;i<t;i++) bfs(a[i]);
  127. if (t==) return dp[a[]][];
  128. g[][]=dp[a[]][]; g[][]=inf;
  129. for (int i=;i<t;i++)
  130. {
  131. g[i][]=min(g[i-][], g[i-][]);
  132. add(g[i][], min(dp[a[i]][], dp[a[i]][]+));
  133. g[i][]=g[i-][];
  134. add(g[i][], dp[a[i]][]);
  135. }
  136. ret=g[t-][];
  137.  
  138. g[][]=dp[a[]][]; g[][]=inf;
  139. for (int i=;i<t;i++)
  140. {
  141. g[i][]=min(g[i-][], g[i-][]);
  142. add(g[i][], min(dp[a[i]][], dp[a[i]][]+));
  143. g[i][]=g[i-][];
  144. add(g[i][], dp[a[i]][]);
  145. }
  146. ret=min(ret, min(g[t-][], g[t-][]));
  147.  
  148. g[][]=dp[a[]][]+; g[][]=inf;
  149. for (int i=;i<t;i++)
  150. {
  151. g[i][]=min(g[i-][], g[i-][]);
  152. add(g[i][], min(dp[a[i]][], dp[a[i]][]+));
  153. g[i][]=g[i-][];
  154. add(g[i][], dp[a[i]][]);
  155. }
  156. ret=min(ret, g[t-][]);
  157.  
  158. return ret;
  159. }

因为是考试时写的所以很长也是没办法的事系列

[POI 2008]Mafia的更多相关文章

  1. [POI 2008&洛谷P3467]PLA-Postering 题解(单调栈)

    [POI 2008&洛谷P3467]PLA-Postering Description Byteburg市东边的建筑都是以旧结构形式建造的:建筑互相紧挨着,之间没有空间.它们共同形成了一条长长 ...

  2. [POI 2008][BZOJ 1132]Tro

    这题我真是无能为力了 这题的做法还是挺简单的 枚举左下角的点做为原点,把其余点按极角排序    PS.是作为原点,如枚举到 k 时,对于所有 p[i] (包括p[k]) p[i]-=p[k] (此处为 ...

  3. bzoj 1112 poi 2008 砖块

    这滞胀题调了两天了... 好愚蠢的错误啊... 其实这道题思维比较简单,就是利用treap进行维护(有人说线段树好写,表示treap真心很模板) 就是枚举所有长度为k的区间,查出中位数,计算代价即可. ...

  4. 解题:POI 2008 Subdivision of Kingdom

    题面 还可以这么搜......学到了(PoPoQQQ orz) 我们最朴素的做法是枚举所有状态(当然可以剪,剪完最终实际状态量也是$C_{26}^{13}$的),然后每次$O(n)$扫一遍判断,大概会 ...

  5. 解题:POI 2008 Plot purchase

    题面 原来看过然后没做,结果板板把这道题改了改考掉了,血亏=.= 首先看看有没有符合条件的点.如果没有开始寻找解,先把所有的大于$2*k$的点设为坏点,然后求最大子矩形,只要一个最大子矩形的权值和超过 ...

  6. 解题:POI 2008 Station

    题面 水水的换根裸题,不过以前还真没做过换根的题 换根的思想就是在DFS中利用树的信息更新出当前点为根时的信息,具体来说一般是考虑子树外和子树内两部分 每个点的答案$ans$就是$ans[fa]+n- ...

  7. [BZOJ 1124][POI 2008] 枪战 Maf

    1124: [POI2008]枪战Maf Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 659  Solved: 259[Submit][Status ...

  8. loj10104 [POI 2008]Blockade

    传送门 分析 我们知道对于一个割点,我们如果去掉它就会使原来的图被分为若干块,则这是我们将所有块包含的点的个数两两相乘即可,而如果不是割点则对于图的连通性没有影响.注意在最后要加上2*(n-1)表示去 ...

  9. [POI 2008] BLO

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=1123 [算法] 首先,如果一个点不是割点,那么,去掉该点后不连通的有序点对就为 : ...

随机推荐

  1. JVM-class文件完全解析-类索引,父类索引和索引集合

    类索引,父类索引和接口索引集合 前面介绍了class文件,从头开始的魔数,次版本号,主版本号,常量池入口,常量池,访问标志.那么再接下来的就是用来确定这个类的继承关系的类索引,父类索引和接口索引集合这 ...

  2. julia解无忧公主的数学时间097.jl

    julia解无忧公主的数学时间097.jl #=""" julia解无忧公主的数学时间097.jl http://mp.weixin.qq.com/s?__biz=MzI ...

  3. jQuery之$('#id')和$('#'+id)

    最近在项目中使用$('#id')时,发现拿到的元素怎么都是空元素,(前提是id是作为变量),纠结了好一阵,使用fire bug也调试了半天终于发现原来$('#id')是使用整体来匹配,即查找id 为i ...

  4. 简单实现web单点登录

    主要参考文档:http://blog.csdn.net/jimmy609/article/details/18605781 1.工程总体结构: 2.修改C:\Windows\System32\driv ...

  5. 面向连接的Socket Server的简单实现(简明易懂)

    一.基本原理 有时候我们需要实现一个公共的模块,需要对多个其他的模块提供服务,最常用的方式就是实现一个Socket Server,接受客户的请求,并返回给客户结果. 这经常涉及到如果管理多个连接及如何 ...

  6. python 优雅的使用正则表达式 ~ 1

    正则表达式简介 正则表达式 , 也称谓 REs , 本质上是一个微小且高度专业化的编程语言. 他被嵌入到许多语言当中 , 例如 python 就是通过 re 模块来提供给我们使用 , 正则表达式 是通 ...

  7. 我与python3擦肩而过(二)—— csv文件头哪去啦?

    在看Python Data Visualization Cookbook 这本书(基于python2),开始时读取csv文件头的时候出现问题.查了资料,又是python3的问题,从这个链接找到答案. ...

  8. Qt中使用随机数

    新建Empty qmake project,命名为UseRand UseRand.pro SOURCES += \ main.cpp QT += core main.cpp #include < ...

  9. 【LeetCode OJ】Populating Next Right Pointers in Each Node II

    Problem Link: http://oj.leetcode.com/problems/populating-next-right-pointers-in-each-node-ii/ OK... ...

  10. Android获取图片资源的4种方式

    1. 图片放在sdcard中 Bitmap imageBitmap = BitmapFactory.decodeFile(path) (path 是图片的路径,跟目录是/sdcard) 2. 图片在项 ...