题目传送门

  传送点

题目大意

  给定$n$个标号依次为$1, 2, \cdots, n$的点,其中一些点被染成一些颜色,剩下的点没有染色。你需要添加一些有向边并将剩下的点染色,满足有向边从编号小的一端指向编号大的一端,图中所有黑白相错的路径的条数与$p$对2取模同余。

  $1\leqslant n\leqslant 10^6$

  想一下如何求DAG中黑白相错的路径的条数。用$g_{i}$表示$i$结尾的路径的条数。

  考虑怎么转移,枚举前一个点,然后$g_{i} += g_{pre}[col_{pre}\neq col_{i}]$。

  这里我们希望知道所有点的$g$的和的奇偶性。我们考虑每次加入一个点,我们希望知道它的$g$的奇偶性就能更新了。

  它更新的时候的奇偶性只与$g_{pre}$的奇偶性以及$g$的颜色有关,因此我们可以将点分为四类:

  • 奇黑点,$g_{p} \equiv 1 \pmod{2} \wedge col_{i} = black$
  • 偶黑点,$g_{p} \equiv 0 \pmod{2} \wedge col_{i} = black$
  • 奇白点,$g_{p} \equiv 1 \pmod{2} \wedge col_{i} = white$
  • 偶白点,$g_{p} \equiv 0 \pmod{2} \wedge col_{i} = white$

  然后假设当前的即将加入的点是白点,那么考虑它的连边

  • 之前的白点对它的奇偶性没有影响,所以这之间的边可以任意连。
  • 偶黑点对它的奇偶性也没有影响,所以这之间的边可以任意连。
  • 考虑奇黑点
    • 如果不存在奇黑点,那么当前点一定是奇白点(它自己的方案)。
    • 如果存在奇黑点,每与一个奇黑点连边就会改变一次奇偶性,那么我们先拿走一个,剩下的任意连,拿走的这一个可以控制这个点方案数的奇偶性(比如考虑这个点之前当前点是奇白点,我希望它是奇白点,那么不连边)。因此恰好一半的任意连边方法使当前点的奇偶性为奇或偶。

  对黑点可以作类似的讨论,然后我们可以愉快地得出结论:

  • 如果当前不存在方案数为奇数的颜色与当前点相反的点,那么之前方案数乘上$2^{i - 1}$转移到当前点方案数为奇数的状态。
  • 否则,对于当前点方案数为奇为偶各加上之前方案数乘$2^{i - 2}$。

  状态用$f_{i, have\_odd\_white, have\_odd\_black, parity}$来表示。

  时间复杂度$O(n)$。

Code

  1. /**
  2. * Codeforces
  3. * Problem#979E
  4. * Accepted
  5. * Time: 31ms
  6. * Memory: 36100k
  7. */
  8. #include <bits/stdc++.h>
  9. using namespace std;
  10. typedef bool boolean;
  11.  
  12. const int N = , M = 1e9 + ;
  13.  
  14. int add(int a, int b) {
  15. a += b;
  16. if (a >= M)
  17. return a - M;
  18. return a;
  19. }
  20.  
  21. int n, p;
  22. int ar[N];
  23. int pow2[N];
  24. int f[N][N][N][N];
  25. int C[N][N];
  26. int Co[N], Ce[N];
  27.  
  28. inline void init() {
  29. scanf("%d%d", &n, &p);
  30. for (int i = ; i <= n; i++)
  31. scanf("%d", ar + i);
  32. }
  33.  
  34. inline void prepare() {
  35. pow2[] = ;
  36. for (int i = ; i <= n; i++)
  37. pow2[i] = add(pow2[i - ], pow2[i - ]);
  38.  
  39. C[][] = ;
  40. for (int i = ; i <= n; i++) {
  41. C[i][] = C[i][i] = ;
  42. for (int j = ; j < n; j++)
  43. C[i][j] = add(C[i - ][j], C[i - ][j - ]);
  44. }
  45.  
  46. for (int i = ; i <= n; i++) {
  47. for (int j = ; j <= n; j++)
  48. if (j & ) {
  49. Co[i] = add(Co[i], C[i][j]);
  50. } else {
  51. Ce[i] = add(Ce[i], C[i][j]);
  52. }
  53. }
  54. }
  55.  
  56. inline void solve() {
  57. f[][][][] = ;
  58. for (int i = ; i <= n; i++)
  59. // enmuerating last status
  60. for (int ob = ; ob < i; ob++) // odd black
  61. for (int eb = ; ob + eb < i; eb++) // even black
  62. for (int ow = ; ob + eb + ow < i; ow++) { // odd white
  63. int lans = f[i - ][ob][eb][ow];
  64. if (!lans)
  65. continue;
  66. int ew = i - ob - eb - ow - ;
  67. if (ar[i] != ) { // here painted in white
  68. int gama = pow2[ow + ew + eb];
  69. f[i][ob][eb][ow] = add(f[i][ob][eb][ow], lans * 1ll * gama % M * Co[ob] % M);
  70. f[i][ob][eb][ow + ] = add(f[i][ob][eb][ow + ], lans * 1ll * gama % M * Ce[ob] % M);
  71. }
  72.  
  73. if (ar[i] != ) { // here painted in black
  74. int gama = pow2[ew + ob + eb];
  75. f[i][ob][eb + ][ow] = add(f[i][ob][eb + ][ow], lans * 1ll * gama % M * Co[ow] % M);
  76. f[i][ob + ][eb][ow] = add(f[i][ob + ][eb][ow], lans * 1ll * gama % M * Ce[ow] % M);
  77. }
  78. }
  79.  
  80. int res = ;
  81. for (int ob = ; ob <= n; ob++)
  82. for (int eb = ; eb + ob <= n; eb++)
  83. for (int ow = ; ow + eb + ob <= n; ow++)
  84. if (((ob + ow) & ) == p)
  85. res = add(res, f[n][ob][eb][ow]);
  86. printf("%d\n", res);
  87. }
  88.  
  89. int main() {
  90. init();
  91. prepare();
  92. solve();
  93. return ;
  94. }

Slower Solution

  1. /**
  2. * Codeforces
  3. * Problem#979E
  4. * Accepted
  5. * Time: 31ms
  6. * Memory: 300k
  7. */
  8. #include <bits/stdc++.h>
  9. using namespace std;
  10. typedef bool boolean;
  11.  
  12. const int N = , M = 1e9 + ;
  13.  
  14. int add(int a, int b) {
  15. a += b;
  16. if (a >= M)
  17. return a - M;
  18. return a;
  19. }
  20.  
  21. int n, p;
  22. int ar[N];
  23. int pow2[N];
  24. int f[N][][][];
  25.  
  26. inline void init() {
  27. scanf("%d%d", &n, &p);
  28. for (int i = ; i <= n; i++)
  29. scanf("%d", ar + i);
  30. pow2[] = ;
  31. for (int i = ; i <= n; i++)
  32. pow2[i] = add(pow2[i - ], pow2[i - ]);
  33. }
  34.  
  35. inline void solve() {
  36. f[][][][] = ;
  37. for (int i = ; i <= n; i++)
  38. // enmuerating last status
  39. for (int hob = ; hob < ; hob++) // exists odd black or not
  40. for (int how = ; how < ; how++) // exists odd white or not
  41. for (int par = ; par < ; par++) {
  42. int lans = f[i - ][hob][how][par];
  43. if (!lans)
  44. continue;
  45. if (ar[i] != ) { // here painted in white
  46. if (!hob)
  47. f[i][][][par ^ ] = add(f[i][][][par ^ ], lans * 1ll * pow2[i - ] % M);
  48. else {
  49. f[i][][][par ^ ] = add(f[i][][][par ^ ], lans * 1ll * pow2[i - ] % M);
  50. f[i][][how][par] = add(f[i][][how][par], lans * 1ll * pow2[i - ] % M);
  51. }
  52. }
  53.  
  54. if (ar[i] != ) { // here painted in black
  55. if (!how)
  56. f[i][][][par ^ ] = add(f[i][][][par ^ ], lans * 1ll * pow2[i - ] % M);
  57. else {
  58. f[i][][][par ^ ] = add(f[i][][][par ^ ], lans * 1ll * pow2[i - ] % M);
  59. f[i][hob][][par] = add(f[i][hob][][par], lans * 1ll * pow2[i - ] % M);
  60. }
  61. }
  62. }
  63. int res = ;
  64. for (int x = ; x < ; x++)
  65. for (int y = ; y < ; y++)
  66. res = add(res, f[n][x][y][p]);
  67. printf("%d\n", res);
  68. }
  69.  
  70. int main() {
  71. init();
  72. solve();
  73. return ;
  74. }

Codeforces 979E Kuro and Topological Parity - 动态规划 - 组合数学的更多相关文章

  1. Codeforces 979E Kuro and Topological Parity(dp)

    题面传送门 题意:有 \(n\) 个点,每个点要么被涂黑,要么被涂白,要么没有颜色. 现在你要: 给没有颜色的点图上颜色(黑色或白色) 在这 \(n\) 个点中连若干条有向边,可以不连通.但是只能从编 ...

  2. cf round 482E Kuro and Topological Parity

    题意:一个长度为$n$的序列,一些地方是$0$,一些地方是$1$,$-1$的地方你可以选择填$0$或者$1$,你可以选择连一些边$x->y$满足$x<y$ 请问有多少种填数并连边的方法,使 ...

  3. Codeforces 835F Roads in the Kingdom - 动态规划

    题目传送门 传送点I 传送点II 传送点III 题目大意 给定一颗基环树,要求删去其中一条边,使得剩下的图形是一棵树,并且最长路的长度最短,求最长路的最短长度. 路径可以分为两部分:跨过环 和 在树内 ...

  4. Codeforces 581F Zublicanes and Mumocrates - 树形动态规划

    It's election time in Berland. The favorites are of course parties of zublicanes and mumocrates. The ...

  5. 【Codeforces 949D】Shake It! 【动态规划】

    参考: http://blog.csdn.net/gjghfd/article/details/77824901 所求的是满足条件的图中“不同构”的数量,意味着操作的顺序是可以忽略的.考虑若干次操作后 ...

  6. Codeforces - 9D - How many trees? - 简单dp - 组合数学

    https://codeforces.com/problemset/problem/9/D 一开始居然还想直接找公式的,想了想还是放弃了.原来这种结构是要动态规划. 状态是知道怎么设了,$t_{nh} ...

  7. codeforces 1284C. New Year and Permutation(组合数学)

    链接:https://codeforces.com/problemset/problem/1284/C 题意:定义一个framed segment,在区间[l,r]中,max值-min值 = r - ...

  8. Codeforces 549C. The Game Of Parity[博弈论]

    C. The Game Of Parity time limit per test 1 second memory limit per test 256 megabytes input standar ...

  9. Codeforces Round #335 Sorting Railway Cars 动态规划

    题目链接: http://www.codeforces.com/contest/606/problem/C 一道dp问题,我们可以考虑什么情况下移动,才能移动最少.很明显,除去需要移动的车,剩下的车, ...

随机推荐

  1. js---根据指定的顺序进行排序

    有一个数据列表,我需要根据根据ID依次来取里面的第9,3,8,4项,具体的实现方法. var arr = [ {id:1,title:'我是第一个'}, {id:2,title:'我是第二个'}, { ...

  2. js 表达式与语句

    引子:表达式和语句很基础,但是有时会犯错,比如: function(){}//报错 (function(){})//不报错 function f(x){ return x + 1 }()//报错 fu ...

  3. Mysql 数据库开发规范

    设计范式参看,DDL与DDL 库表基础规范 1.注释 每个表要添加注释,对 status 型需指明主要值的含义,如”0-离线,1-在线” 2.表的字段数量 单表字段数一般考虑上限为 30左右,再多的话 ...

  4. openssl内核升级

    由于工作需要,防止安全漏洞需要对openssl升级现在整理出centos6.8和ubuntu14.4升级 centos升级openssl 1.首先去OpenSSL的网站 https://www.ope ...

  5. 剑指offer——python【第16题】合并两个有序链表

    题目描述 将两个有序链表合并为一个新的有序链表并返回.新链表是通过拼接给定的两个链表的所有节点组成的. 示例: 输入:1->2->4, 1->3->4 输出:1->1-& ...

  6. Docker win10安装

    因为虚拟机还没装好,所以现在win10上安装Docker 1.首先下载Docker Toolbox,因为Docker for windows需要win10专业版或者其他64位版本,我的系统虽然也是wi ...

  7. div加链接 html给div加超链接实现点击div跳转的方法[申明:来源于网络]

    div加链接 html给div加超链接实现点击div跳转的方法[申明:来源于网络] 地址:http://www.cdxwcx.com/faq/htmldivLink.html

  8. HDU 2612 - Find a way - [BFS]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2612 Problem DescriptionPass a year learning in Hangz ...

  9. vimrc同步文档

    目录 vimrc ims.vim vimrc if has("syntax") syntax on endif set nocompatible "取消vi 兼容模式 & ...

  10. TZOJ:区间问题

    描述 有n项工作,每项工作分别在 si时间开始,ti时间结束.对于每项工作你选择参与与否,如果选择 了参与,那么自始至终就必须全程参与.参与工作的时间段不可以重叠(即使是开始的瞬间和结束的瞬间重叠也是 ...