您的位置:首页 > 其它

【TCO 2012】2A EvenPaths

2015-09-29 10:44 393 查看


2A EvenPaths


Description

给出一张拓扑图,其中有一些点可能有障碍,这样的所有可能局面中,从0到1的不同路径有偶数条的局面有多少种。


Difficulty

★★★★★


Main Algorithm

分段(meet in middle)

DP

快速沃尔士变换


Complexity




















Solution

由于有





个局面,所以需要用一些方法来处理。

我们将拓扑图按一个割分成两部分,每一部分都有



个障碍。

对于一个部分,可以暴力





枚举后DP出从0/1到它的方案数。

这样,关键就是将两半的答案合并。

我们将与0相连的点的贡献(即往连向1的点上应有的转移)处理为一个向量,其中i的权值表示在1集合中障碍点的状态压位后为i的由0集合贡献的方案数。

另一个向量为从1集合对应点到1号点的方案数。

假如两半局面合并了,合法方案为那些临界点的方案数和为偶数的方案。故需要一个合并方法。

可以发现,对应点的合并的结果是将前一半的结果与后一半逻辑与起来。那么其实我们是要算一个卷积:























类似于SRM 518 NIM,我们构造一个变换来加速这个卷积。

由于逻辑与运算是位独立的,不妨设

















.

那么































.

可以验证这个变换是可以满足上述卷积的。

其逆显然为

































.

故只需要用这个变换就能在















的时间内解决卷积了。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <cmath>
#define Rep(i, x, y) for (int i = x; i <= y; i ++)
#define Dwn(i, x, y) for (int i = x; i >= y; i --)
#define RepE(i, x) for(int i = pos[x]; i; i = g[i].nex)
#define RepG(i, x) for(int i = pos2[x]; i; i = g2[i].nex)
using namespace std;
typedef long long LL;
const int M = 300005, N = 53;
struct Edge { int y, nex; } g[N * N * 2], g2[N * N * 2];
LL ans, p[M], q[M];
int n, m, in
, in2
, sz, sz2, pos
, pos2
, In
, In2
, que
, hd, tl, n1, n0, num;
int d
, f
, b
, f0
, c
, a1
;
class EvenPaths {
public:
void Init(int x, int y) { g[++ sz] = (Edge) { y, pos[x] }, pos[x] = sz; In[y] ++; }
void Init2(int x, int y) { g2[++ sz2] = (Edge) { y, pos2[x] }, pos2[x] = sz2; In2[y] ++; }
void Topo() {
que[hd = tl = 1] = 0, f[0] = 1, in[0] = In[0] = n + 10;
Rep(i, 1, n) {
in[i] = In[i];
if (!in[i]) que[++ tl] = i, f[i] = 0;
}
while (hd <= tl) {
int x = que[hd ++];
RepE(i, x) {
int y = g[i].y; in[y] --;
if (!in[y]) {
if (b[y] && num < 16) c[y] = 1, num ++;
que[++ tl] = y;
}
}
}
}
void Build() {
n0 = (1 << num) - 1;
Rep(i, 0, n) if (b[i] && !c[i]) a1[++ n1] = i;
Rep(i, 0, n0) {
int k = i;
Rep(j, 0, n) if (c[j]) {
d[j] = k % 2, k >>= 1;
}
memset(f, 0, sizeof(f));
que[hd = tl = 1] = 0, f[0] = 1;
Rep(j, 0, n) { in[j] = In[j]; if (!in[j]) que[++ tl] = j; }
while (hd <= tl) {
int x = que[hd ++];
if ((b[x] && !c[x]) || d[x]) {
RepE(j, x) {
int y = g[j].y; in[y] --;
if (!in[y]) que[++ tl] = y;
}
continue ;
}
RepE(j, x) {
int y = g[j].y; in[y] --;
f[y] ^= f[x];
if (!in[y]) que[++ tl] = y;
}
}
k = 0;
Rep(j, 1, n1) if (f[ a1[j] ]) k += (1 << (j-1));
if (f[1]) k += 1 << n1;
p[k] ++;
}
m = (1 << (n1 + 1)) - 1;
Rep(i, 0, (1 << n1) - 1) {
int k = i;
Rep(j, 1, n1) {
d[ a1[j] ] = k % 2, k >>= 1;
}
memset(f0, 0, sizeof(f0));
que[hd = tl = 1] = 1, f0[1] = 1, in[1] = n + 1, in[0] = In2[0];
Rep(j, 2, n) { in[j] = In2[j]; if (!in[j]) que[++ tl] = j; }
while (hd <= tl) {
int x = que[hd ++];
if (d[x]) {
RepG(j, x) {
int y = g2[j].y; in[y] --;
if (!in[y]) que[++ tl] = y;
}
continue ;
}
RepG(j, x) {
int y = g2[j].y; in[y] --;
f0[y] ^= f0[x];
if (!in[y]) que[++ tl] = y;
}
}
k = 1 << n1;
Rep(j, 1, n1) if (!d[ a1[j] ] && f0[ a1[j] ]) k += (1 << (j-1));
q[k] ++;
}
}
void FWT(LL *b, int l, int r, int v) {
if (l == r) return ;
int mid = (l + r) >> 1;
FWT(b, l, mid, v), FWT(b, mid + 1, r, v);
Rep(i, 0, mid - l) b[i + l] += b[mid + i + 1] * v;
}
void Calc() {
FWT(p, 0, m, 1), FWT(q, 0, m, 1);
Rep(i, 0, m) p[i] *= q[i];
FWT(p, 0, m, -1);
Rep(i, 0, m) {
int k = i, k0 = 0;
while (k) k0 += (k % 2), k >>= 1;
if (k0 % 2 == 0) ans += p[i];
}
}
long long theCount(vector <string> maze, string rooms) {
n = maze.size() - 1;
Rep(i, 0, n) {
Rep(j, 0, n) if (maze[i][j] == 'Y') Init(i, j), Init2(j, i);
b[i] = (rooms[i] == '?');
}
Topo();
Build(), Calc();
return ans;
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: