Codeforces 979E Kuro and Topological Parity - 动态规划 - 组合数学
题目传送门
题目大意
给定$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
/**
* Codeforces
* Problem#979E
* Accepted
* Time: 31ms
* Memory: 36100k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; const int N = , M = 1e9 + ; int add(int a, int b) {
a += b;
if (a >= M)
return a - M;
return a;
} int n, p;
int ar[N];
int pow2[N];
int f[N][N][N][N];
int C[N][N];
int Co[N], Ce[N]; inline void init() {
scanf("%d%d", &n, &p);
for (int i = ; i <= n; i++)
scanf("%d", ar + i);
} inline void prepare() {
pow2[] = ;
for (int i = ; i <= n; i++)
pow2[i] = add(pow2[i - ], pow2[i - ]); C[][] = ;
for (int i = ; i <= n; i++) {
C[i][] = C[i][i] = ;
for (int j = ; j < n; j++)
C[i][j] = add(C[i - ][j], C[i - ][j - ]);
} for (int i = ; i <= n; i++) {
for (int j = ; j <= n; j++)
if (j & ) {
Co[i] = add(Co[i], C[i][j]);
} else {
Ce[i] = add(Ce[i], C[i][j]);
}
}
} inline void solve() {
f[][][][] = ;
for (int i = ; i <= n; i++)
// enmuerating last status
for (int ob = ; ob < i; ob++) // odd black
for (int eb = ; ob + eb < i; eb++) // even black
for (int ow = ; ob + eb + ow < i; ow++) { // odd white
int lans = f[i - ][ob][eb][ow];
if (!lans)
continue;
int ew = i - ob - eb - ow - ;
if (ar[i] != ) { // here painted in white
int gama = pow2[ow + ew + eb];
f[i][ob][eb][ow] = add(f[i][ob][eb][ow], lans * 1ll * gama % M * Co[ob] % M);
f[i][ob][eb][ow + ] = add(f[i][ob][eb][ow + ], lans * 1ll * gama % M * Ce[ob] % M);
} if (ar[i] != ) { // here painted in black
int gama = pow2[ew + ob + eb];
f[i][ob][eb + ][ow] = add(f[i][ob][eb + ][ow], lans * 1ll * gama % M * Co[ow] % M);
f[i][ob + ][eb][ow] = add(f[i][ob + ][eb][ow], lans * 1ll * gama % M * Ce[ow] % M);
}
} int res = ;
for (int ob = ; ob <= n; ob++)
for (int eb = ; eb + ob <= n; eb++)
for (int ow = ; ow + eb + ob <= n; ow++)
if (((ob + ow) & ) == p)
res = add(res, f[n][ob][eb][ow]);
printf("%d\n", res);
} int main() {
init();
prepare();
solve();
return ;
}
Slower Solution
/**
* Codeforces
* Problem#979E
* Accepted
* Time: 31ms
* Memory: 300k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean; const int N = , M = 1e9 + ; int add(int a, int b) {
a += b;
if (a >= M)
return a - M;
return a;
} int n, p;
int ar[N];
int pow2[N];
int f[N][][][]; inline void init() {
scanf("%d%d", &n, &p);
for (int i = ; i <= n; i++)
scanf("%d", ar + i);
pow2[] = ;
for (int i = ; i <= n; i++)
pow2[i] = add(pow2[i - ], pow2[i - ]);
} inline void solve() {
f[][][][] = ;
for (int i = ; i <= n; i++)
// enmuerating last status
for (int hob = ; hob < ; hob++) // exists odd black or not
for (int how = ; how < ; how++) // exists odd white or not
for (int par = ; par < ; par++) {
int lans = f[i - ][hob][how][par];
if (!lans)
continue;
if (ar[i] != ) { // here painted in white
if (!hob)
f[i][][][par ^ ] = add(f[i][][][par ^ ], lans * 1ll * pow2[i - ] % M);
else {
f[i][][][par ^ ] = add(f[i][][][par ^ ], lans * 1ll * pow2[i - ] % M);
f[i][][how][par] = add(f[i][][how][par], lans * 1ll * pow2[i - ] % M);
}
} if (ar[i] != ) { // here painted in black
if (!how)
f[i][][][par ^ ] = add(f[i][][][par ^ ], lans * 1ll * pow2[i - ] % M);
else {
f[i][][][par ^ ] = add(f[i][][][par ^ ], lans * 1ll * pow2[i - ] % M);
f[i][hob][][par] = add(f[i][hob][][par], lans * 1ll * pow2[i - ] % M);
}
}
}
int res = ;
for (int x = ; x < ; x++)
for (int y = ; y < ; y++)
res = add(res, f[n][x][y][p]);
printf("%d\n", res);
} int main() {
init();
solve();
return ;
}
Codeforces 979E Kuro and Topological Parity - 动态规划 - 组合数学的更多相关文章
- Codeforces 979E Kuro and Topological Parity(dp)
题面传送门 题意:有 \(n\) 个点,每个点要么被涂黑,要么被涂白,要么没有颜色. 现在你要: 给没有颜色的点图上颜色(黑色或白色) 在这 \(n\) 个点中连若干条有向边,可以不连通.但是只能从编 ...
- cf round 482E Kuro and Topological Parity
题意:一个长度为$n$的序列,一些地方是$0$,一些地方是$1$,$-1$的地方你可以选择填$0$或者$1$,你可以选择连一些边$x->y$满足$x<y$ 请问有多少种填数并连边的方法,使 ...
- Codeforces 835F Roads in the Kingdom - 动态规划
题目传送门 传送点I 传送点II 传送点III 题目大意 给定一颗基环树,要求删去其中一条边,使得剩下的图形是一棵树,并且最长路的长度最短,求最长路的最短长度. 路径可以分为两部分:跨过环 和 在树内 ...
- Codeforces 581F Zublicanes and Mumocrates - 树形动态规划
It's election time in Berland. The favorites are of course parties of zublicanes and mumocrates. The ...
- 【Codeforces 949D】Shake It! 【动态规划】
参考: http://blog.csdn.net/gjghfd/article/details/77824901 所求的是满足条件的图中“不同构”的数量,意味着操作的顺序是可以忽略的.考虑若干次操作后 ...
- Codeforces - 9D - How many trees? - 简单dp - 组合数学
https://codeforces.com/problemset/problem/9/D 一开始居然还想直接找公式的,想了想还是放弃了.原来这种结构是要动态规划. 状态是知道怎么设了,$t_{nh} ...
- codeforces 1284C. New Year and Permutation(组合数学)
链接:https://codeforces.com/problemset/problem/1284/C 题意:定义一个framed segment,在区间[l,r]中,max值-min值 = r - ...
- 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 ...
- Codeforces Round #335 Sorting Railway Cars 动态规划
题目链接: http://www.codeforces.com/contest/606/problem/C 一道dp问题,我们可以考虑什么情况下移动,才能移动最少.很明显,除去需要移动的车,剩下的车, ...
随机推荐
- Python Django 配置QQ邮箱发送邮件
一.实验环境 Python2.7 + Django1.10.0 二.获取QQ邮箱授权码 1.什么是授权码? 授权码是QQ邮箱推出的,用于登录第三方客户端的专用密码. 适用于登录以下服务:POP3/IM ...
- JavaScript原型、闭包、继承和原型链等等总结
参考:http://www.cnblogs.com/wangfupeng1988/tag/%E5%8E%9F%E5%9E%8B%E9%93%BE/
- 写jquery插件(转载)
如今做web开发,jquery 几乎是必不可少的,就连vs神器在2010版本开始将Jquery 及ui 内置web项目里了.至于使用jquery好处这里就不再赘述了,用过的都知道.今天我们来讨论下jq ...
- Assignments---(贪心)
Assignments Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- 【持续集成】GIT+jenkins+sonar——GIT
一.GIT基础 1.1 git简介 linus用C语言编写 2005年诞生 分布式管理系统 速度快.适合大规模.跨地区多人协同开发 1.2 本地管理.集中式.分布式 1.3 git安装 #CentOS ...
- 转 基于Excel参数化你的Selenium2测试
转载:https://blog.csdn.net/zhusongziye/article/details/80100375 前言 今天我们就如何使用xlrd模块来进行python selenium2 ...
- mysql InnoDB锁等待的查看及分析
说明:前面已经了解了InnoDB关于在出现锁等待的时候,会根据参数innodb_lock_wait_timeout的配置,判断是否需要进行timeout的操作,本文档介绍在出现锁等待时候的查看及分析处 ...
- centos7忘记root密码重置
1.重启服务器,选择内存按“e”编辑 2.找到下入内容 3.将上图中标记的ro改为rw init=/sysroot/bin/sh 4.按Ctrl+x进入单用户模式 5.执行命令chroot /sysr ...
- 解决端口耗尽问题: tcp_tw_reuse、tcp_timestamps
一.本地端口有哪些可用 首先,需要了解到TCP协议中确定一条TCP连接有4要素:local IP, local PORT, remote IP, remote PORT.这个四元组应该是唯一的. 在我 ...
- python类中的内置函数
__init__():__init__方法在类的一个对象被建立时,马上运行.这个方法可以用来对你的对象做一些你希望的初始化.注意,这个名称的开始和结尾都是双下划线.代码例子: #!/usr/bin/p ...