題意
題解
朴素的就是 \(O(n3^n)\) dp 寫了一下有 \(50pts\) ... 大概就是每個點有三個狀態 , 考慮了但不在獨立集中 , 考慮了並且在獨立集中 , 還沒考慮 . 轉移就很顯然了 qwq
然后要優化嘛 , 把其中兩個狀態合起來 , 也就是分成考慮了和沒考慮了的兩種 .
其中考慮了的那種 , 只會存在兩種狀態 , 要么是在獨立集內 , 要么就是與獨立集聯通 , 沒有考慮的 絕對不和獨立集聯通 就行了 .
然后我們枚舉一個集合 , 考慮強制把一個點選進來 . 如果要選它 , 那么它周圍的一圈都不能去選 .
為了使這個 dp 不存在后效性 , 我們不能讓之后的選的點連得點存在於獨立集中 , 我們把他周圍一圈的都放進來就行了 .
也就是說當前維護的集合 , 會被最外面沒有存在於獨立集中的一圈給包圍住 .
然后連上來的時候會有很多種排列的方式 , 直接乘上一個排列數就行了 . (相當於預留位置)
最后算答案因為是概率 , 除以 \(\frac{1}{n!}\) 就行了 .
這些我都是問 DOFY 才懂的 , 還是太菜啦 ~
具體來說 方程是這樣的 (\(\displaystyle f_{i,s}\) 當前選了 \(i\) 個點 , 考慮過的集合是 \(s\) , 與 \(k\) 相鄰的所有點(包括它自己)的集合為 \(w_k\) ):
時間復雜度是 \(O(n^2 2^n)\) 可以通過此題了 .
然后進行一波優化 , 對於一個確定的考慮過的集合 \(s\) 那么它選取最大獨立集 , 是選取全局的最大獨立集的必要條件 .
(這個應該顯然吧 ... 因為最外圈你不要的話 , 如果里面不是最大獨立集的話 , 外面取得最大也達不到全局最大)
那么第一位考慮選點的就可以不要了 , 時間復雜度就是 \(O(n2^n)\) .
這樣寫了一下 莫名奇妙就是 LOJ 最快的了 ?
代碼
#include <bits/stdc++.h>
#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
using namespace std;
inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}
inline int read() {
int x = 0, fh = 1; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
return x * fh;
}
void File() {
#ifdef zjp_shadow
freopen ("2540.in", "r", stdin);
freopen ("2540.out", "w", stdout);
#endif
}
const int N = 20;
int n, m, Con[N];
typedef long long ll;
const int Mod = 998244353;
ll fpm(ll x, int power) {
ll inv = 1;
for (; power; power >>= 1, (x *= x) %= Mod)
if (power & 1) (inv *= x) %= Mod;
return inv;
}
ll fac[N + 5], ifac[N + 5];
void Init(int maxn) {
fac[0] = ifac[0] = 1;
For (i, 1, maxn) fac[i] = fac[i - 1] * i % Mod;
ifac[maxn] = fpm(fac[maxn], Mod - 2);
Fordown (i, maxn - 1, 1) ifac[i] = ifac[i + 1] * (i + 1) % Mod;
}
int dp[1 << N], bit[1 << N], MaxSize[1 << N];;
inline int A(int n, int m) { if (m > n || n < 0 || m < 0) return 0; return fac[n] * ifac[n - m] % Mod; }
int main () {
File();
n = read(); m = read(); Init(n);
For (i, 1, m) {
int u = read() - 1, v = read() - 1;
Con[u] |= (1 << v);
Con[v] |= (1 << u);
}
For (i, 0, n - 1) Con[i] |= (1 << i);
dp[0] = 1;
int maxsta = (1 << n) - 1;
For (i, 0, maxsta) bit[i] = bit[i >> 1] + (i & 1);
For (i, 0, maxsta) if (dp[i]) {
For (j, 0, n - 1) if (!((1 << j) & i)) {
register int Next = i | Con[j];
if (chkmax(MaxSize[Next], MaxSize[i] + 1)) dp[Next] = 0;
if (MaxSize[Next] == MaxSize[i] + 1) (dp[Next] += 1ll * dp[i] * A(n - bit[i] - 1, bit[Con[j] ^ (Con[j] & i)] - 1) % Mod) %= Mod;
}
}
printf ("%lld\n", 1ll * dp[maxsta] * ifac[n] % Mod);
return 0;
}