给定
对于 FZT(子集计数)的更具体说明可以参考 FZT - 子集计数学习笔记。
考虑 FZT,显然令
令
不难想到,若
考虑如何转移
可以尝试理解一下这个转移,我们要保证
然后发现,这个东西是假的。不难想到,假设我们考虑一个将
于是转移优化为:
然后因为我们要保证
同时不难对于初始值,存在
然后考虑答案,不难想到,对于点
然后这个求解的复杂度为
最终复杂度为
Tips:对于枚举子集的过程应该不用多说,令 for(int S = Smx; S; S = (S - 1) & Smx)
,具体证明这里不再赘述,可以网上直接搜一下。
Tips:然后关于前面说的枚举子集和子集的子集的复杂度,这个东西用组合数写一下不难证明,总之枚举
xxxxxxxxxx
881
2
3
4
5
6
7
8
9
10
11using namespace std;
12
13mt19937 rnd(random_device{}());
14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
15bool rnddd(int x){return rndd(1, 100) <= x;}
16
17typedef unsigned int uint;
18typedef unsigned long long unll;
19typedef long long ll;
20typedef long double ld;
21
22
23
24
25
26template < typename T = int >
27inline T read(void);
28
29int N, M;
30struct Edge{
31 Edge* nxt;
32 int to;
33 OPNEW;
34}ed[2100];
35ROPNEW(ed);
36Edge* head[20];
37ll F[MAX_STATUS], G[MAX_STATUS];
38ll pow2[500];
39ll ans[20];
40
41int main(){
42 pow2[0] = 1;
43 for(int i = 1; i <= 300; ++i)pow2[i] = pow2[i - 1] * 2 % MOD;
44 N = read(), M = read();
45 const int Smx = (1 << N) - 1;
46 for(int i = 1; i <= M; ++i){
47 int s = read(), t = read();
48 head[s] = new Edge{head[s], t};
49 }F[0] = G[0] = 1;
50 for(int S = Smx; S; S = (S - 1) & Smx){
51 int cnt(0);
52 for(int p = 1; p <= N; ++p)
53 if(EXIST(p))
54 for(auto i = head[p]; i; i = i->nxt)
55 if(EXIST(SON))++cnt;
56 G[S] = pow2[cnt];
57 }
58 for(int S = 1; S <= Smx; ++S){
59 for(int T = (S - 1) & S; T; T = (T - 1) & S)
60 if(T & 1)
61 (F[S] += F[T] * G[S ^ T] % MOD) %= MOD;
62 F[S] = (G[S] - F[S] + MOD) % MOD;
63 }
64 for(int i = 2; i <= N; ++i)
65 for(int S = Smx; S; S = (S - 1) & Smx)
66 if(EXIST(i) && EXIST(1))(ans[i] += F[S] * G[S ^ Smx] % MOD) %= MOD;
67 for(int i = 2; i <= N; ++i)printf("%lld\n", ans[i]);
68 // for(int S = Smx; S; S = (S - 1) & Smx)
69 // cout << "G[" << bitset < 6 >(S) << "] = " << G[S] << ", F = " << F[S] << endl;
70 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
71 return 0;
72}
73
74template < typename T >
75inline T read(void){
76 T ret(0);
77 int flag(1);
78 char c = getchar();
79 while(c != '-' && !isdigit(c))c = getchar();
80 if(c == '-')flag = -1, c = getchar();
81 while(isdigit(c)){
82 ret *= 10;
83 ret += int(c - '0');
84 c = getchar();
85 }
86 ret *= flag;
87 return ret;
88}
update-2022_12_05 初稿