给定
对于 FZT(子集计数)的更具体说明可以参考 FZT - 子集计数学习笔记。
考虑 FZT,显然令
令
不难想到,若
考虑如何转移
可以尝试理解一下这个转移,我们要保证
然后发现,这个东西是假的。不难想到,假设我们考虑一个将
于是转移优化为:
然后因为我们要保证
同时不难对于初始值,存在
然后考虑答案,不难想到,对于点
然后这个求解的复杂度为
最终复杂度为
Tips:对于枚举子集的过程应该不用多说,令 for(int S = Smx; S; S = (S - 1) & Smx),具体证明这里不再赘述,可以网上直接搜一下。
Tips:然后关于前面说的枚举子集和子集的子集的复杂度,这个东西用组合数写一下不难证明,总之枚举
xxxxxxxxxx88123
45678910
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
22232425
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 初稿