图计数相关
由于我发现最近遇到了一堆图计数相关的东西,并且发现自己的技术能力太菜了,遂来学。
P6846 CEOI2019 Amusement Park
不难发现这个题目本质上要求的东西就是无向图的边定向成一个
这里最启发性的东西就是在
那么考虑枚举
但是这样会算重,具体如何呢?由于有可能
qwq
#include<bits/stdc++.h> #define ll long long using namespace std; const int N = 20 + 1, M = N * N + 10, maxS = (1ll << N) + 10; const ll mod = 998244353; void ADD(ll &x, ll y){ x += y; (x >= mod) ? (x -= mod) : x; } int n, m, con[N], pd[maxS], pc[maxS]; ll f[maxS]; signed main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> n >> m; for(int i = 1; i <= m; i++){ int x, y; cin >> x >> y; x--; y--; con[x] |= (1ll << y); con[y] |= (1ll << x); } f[0] = 1; for(int S = 1; S < (1ll << n); S++){ int st = 0; pc[S] = pc[S >> 1] + (S & 1); for(int i = 0; i < n; i++) if(S & (1ll << i)) st |= con[i]; pd[S] = (!(S & st)); //cout << S << " " << st << " " << pd[S] << "\n"; for(int S0 = S; S0; S0 = S & (S0 - 1)){ if(!pd[S0]) continue; //cout << S << " " << S0 << " " << f[S ^ S0] << "\n"; ADD(f[S], f[S ^ S0] * ((pc[S0] & 1ll) ? 1ll : (mod - 1ll)) % mod); } //cout << S << " " << f[S] << "\n"; } cout << f[(1ll << n) - 1] * m % mod * ((mod + 1) / 2) % mod; return 0; }
ABC306Ex Balance Scale
这个题在上个题目中加入了一个连无向边的选择,于是扣掉的点不一定是一个独立集。考虑有一些连通块,那么显然一个联通块中的边都是无向边,可以看做一个大点。即容斥系数变成了
qwq
#include<bits/stdc++.h> #define ll long long #define pb emplace_back using namespace std; const int N = 17 + 1, V = (1ll << N) + 10; const ll mod = 998244353; int n, pc[V], m, vis[N]; ll f[V]; vector<int> vec[N]; void dfs(int u, int S){ vis[u] = 1; for(auto v : vec[u]) if((S & (1ll << v)) && (!vis[v])) dfs(v, S); } void ADD(ll& x, ll y){x += y; (x >= mod) ? x -= mod : 0;} signed main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> n >> m; for(int i = 1; i <= m; i++){ int x, y; cin >> x >> y; x--; y--; vec[x].pb(y); vec[y].pb(x); } for(int S = 1; S < (1ll << n); S++){ for(int i = 0; i < n; i++) vis[i] = 0; for(int i = 0; i < n; i++) if(!vis[i] && (S & (1ll << i))) dfs(i, S), pc[S]++; } f[0] = 1; for(int S = 1; S < (1ll << n); S++){ for(int S0 = S; S0; S0 = S & (S0 - 1)){ ADD(f[S], f[S ^ S0] * ((pc[S0] & 1) ? 1ll : (mod - 1)) % mod); } } cout << f[(1ll << n) - 1]; return 0; }
P11714 清华集训 2014 主旋律
还是考虑记
即枚举缩点之后的零度点。但是显然这样还是会算重,其原理和
但是写一下发现这样还是会算重,其实问题就出在
qwq
#include<bits/stdc++.h> #define ll long long //#define int long long #define pir pair<int, ll> #define fi first #define se second #define pb emplace_back #define inv(x) qpow(x, mod - 2) using namespace std; const int N = (1ll << 16) + 5, M = (1ll << 16) + 5; const ll mod = 1e9 + 7; inline void chkmin(ll& x, ll y){if(y < x) x = y;} inline void chkmax(ll& x, ll y){if(y > x) x = y;} inline void ADD(ll& x, ll y){x += y; (x >= mod) ? (x -= mod) : 0;} inline void MUL(ll& x, ll y){x = x * y % mod;} inline ll qpow(ll x, int y){ ll ret = 1; for(; y; y >>= 1, MUL(x, x)) if(y & 1) MUL(ret, x); return ret; } inline int lowbit(int x){return x & -x;} int n, m, con[M], lg[N], pc[M]; ll f[M], g[M], pw2[N], all[M]; inline int cntCon(int S, int T){ int ret = 0; for(int s0 = S; s0; s0 -= lowbit(s0)) ret += pc[con[lg[lowbit(s0)]] & T]; return ret; } signed main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> n >> m; for(int i = 1; i <= m; i++){ int x, y; cin >> x >> y; x--; y--; con[x] |= (1ll << y); } pw2[0] = 1; for(int i = 0; i < n; i++) lg[(1ll << i)] = i; for(int i = 1; i < N; i++) pw2[i] = pw2[i - 1] * 2ll % mod, pc[i] = pc[i >> 1] + (i & 1); for(int S = 1; S < (1ll << n); S++){ int lb = lowbit(S); all[S] = all[S ^ lb] + cntCon(lb, S ^ lb) + cntCon(S ^ lb, lb); for(int nS = S ^ lb, s0 = nS, ls = nS; ls; ls = s0, s0 = nS & (s0 - 1)) ADD(g[S], mod - f[s0 | lb] * g[nS ^ s0] % mod); for(int s0 = S; s0; s0 = S & (s0 - 1)) ADD(f[S], mod - pw2[cntCon(s0, S ^ s0) + all[S ^ s0]] * g[s0] % mod); ADD(f[S], pw2[all[S]]); ADD(g[S], f[S]); } cout << f[(1 << n) - 1]; return 0; }
本文作者:Little_corn
本文链接:https://www.cnblogs.com/little-corn/p/18751278
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步