Description
给定一个
K
个点
得到的图的补图的哈密顿路径条数。
请输出答案对
Solution
好神的题~
转化成某些边不能走。
考虑容斥,把题目转化为模板图中某些边必须要走。
记
fe
表示走了
e
条不合法的路径的方案数。
那么可以得到模板图缩了这些路径以后剩下
n
个图放在一起就是卷积的形式。
用
然后容斥就可以通过
hx
得到
0
<script type="math/tex" id="MathJax-Element-16">0</script>对同类点在一起的方案数。
// BEGIN CUT HERE
// END CUT HERE
#line 5 "HamiltonianPaths.cpp"
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int GR = 3;
const int K = 15;
const int N = 50505;
const int M = N * K << 2;
const int MOD = 998244353;
int f[1 << K][K], g[1 << K][K * K];
struct edge {
int to, next;
edge(int t = 0, int n = 0):to(t), next(n) {}
};
edge G[K * K * 2];
int head[K];
int inv[M], fac[M];
int n, m, k, Gcnt, x, y, U;
int w[2][M];
int R[M], ans[M];
int num, L, l, Ans;
class HamiltonianPaths {
public:
inline void AddEdge(int from, int to) {
G[++Gcnt] = edge(to, head[from]); head[from] = Gcnt;
G[++Gcnt] = edge(from, head[to]); head[to]= Gcnt;
}
inline void Add(int &x, int a) {
x = (x + a) % MOD;
}
inline int Pow(int a, int b) {
int c = 1;
while (b) {
if (b & 1) c = (ll)c * a % MOD;
b >>= 1; a = (ll)a * a % MOD;
}
return c;
}
inline int Inv(int x) {
return Pow(x, MOD - 2);
}
void Pre(int n) {
inv[1] = 1;
for (int i = 2; i <= n; i++)
inv[i] = (ll)(MOD - MOD / i) * inv[MOD % i] % MOD;
fac[0] = inv[0] = 1;
for (int i = 1; i <= n; i++) {
fac[i] = (ll)fac[i - 1] * i % MOD;
inv[i] = (ll)inv[i - 1] * inv[i] % MOD;
}
int g = Pow(GR, (MOD - 1) / n);
int ig = Inv(g); num = n;
w[0][0] = w[1][0] = 1;
for (int i = 1; i <= n; i++) {
w[0][i] = (ll)w[0][i - 1] * ig % MOD;
w[1][i] = (ll)w[1][i - 1] * g % MOD;
}
for (int i = 1; i < n; i++)
R[i] = (R[i >> 1] >> 1) | ((i & 1) << L);
}
inline void FFT(int *a, int n, int r) {
static int x, y, INV;
for (int i = 0; i < n; i++)
if (R[i] > i) swap(a[i], a[R[i]]);
for (int i = 1; i < n; i <<= 1)
for (int j = 0; j < n; j += (i << 1))
for (int k = 0; k < i; k++) {
x = a[j + k];
y = (ll)a[j + k + i] * w[r][num / (i << 1) * k] % MOD;
a[j + k] = (x + y) % MOD;
a[j + k + i] = (x - y + MOD) % MOD;
}
if (!r) {
INV = Inv(n);
for (int i = 0; i < n; i++)
a[i] = (ll)a[i] * INV % MOD;
}
}
int main(void) {
cout << Ans << endl;
return 0;
}
int countPaths(int k, vector <int> a, vector <int> b, int n) {
U = 1 << k; Pre(n * k); m = a.size();
Gcnt = 0; memset(head, 0, sizeof head);
Ans = 0;
memset(f, 0, sizeof f);
memset(g, 0, sizeof g);
memset(ans, 0, sizeof ans);
for (int i = 1; i <= m; i++)
AddEdge(a[i - 1] + 1, b[i - 1] + 1);
for (int i = 1; i <= k; i++) f[1 << i - 1][i] = 1;
for (int S = 1; S < U; S++)
for (int i = 1; i <= k; i++)
if (((S >> i - 1) & 1) && f[S][i])
for (int j = head[i]; j; j = G[j].next)
if (!((S >> G[j].to - 1) & 1))
Add(f[S | (1 << G[j].to - 1)][G[j].to], f[S][i]);
for (int S = 1; S < U; S++)
for (int i = 1; i <= k; i++)
Add(*f[S], f[S][i]);
g[0][0] = 1;
for (int S = 0; S < U; S++)
for (int e = 1; e <= k; e++)
for (int T = S; T; T = (T - 1) & S)
Add(g[S][e], (ll)g[S ^ T][e - 1] * *f[T] % MOD);
for (l = 1; l <= n * k; l <<= 1) L++; l <<= 1;
Pre(l);
for (int i = 1; i <= k; i++) {
Add(ans[i], (ll)g[U - 1][i] * inv[i] % MOD);
}
FFT(ans, l, 1);
for (int i = 0; i < l; i++) ans[i] = Pow(ans[i], n);
FFT(ans, l, 0);
for (int i = 1; i <= n * k; i++) {
if ((n * k - i) & 1) Add(Ans, MOD - (ll)fac[i] * ans[i] % MOD);
else Add(Ans, (ll)fac[i] * ans[i] % MOD);
}
return Ans;
}
// BEGIN CUT HERE
public:
void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); if ((Case == -1) || (Case == 4)) test_case_4(); if ((Case == -1) || (Case == 5)) test_case_5(); if ((Case == -1) || (Case == 6)) test_case_6(); }
private:
template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); }
void verify_case(int Case, const int &Expected, const int &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } }
void test_case_0() { int Arg0 = 3; int Arr1[] = {0,1}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = {1,2}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 2; int Arg4 = 152; verify_case(0, Arg4, countPaths(Arg0, Arg1, Arg2, Arg3)); }
void test_case_1() { int Arg0 = 12; int Arr1[] = {}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = {}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 10000; int Arg4 = 129246395; verify_case(1, Arg4, countPaths(Arg0, Arg1, Arg2, Arg3)); }
void test_case_2() { int Arg0 = 5; int Arr1[] = {0,1,2,3,4}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = {1,2,3,4,0}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 1; int Arg4 = 10; verify_case(2, Arg4, countPaths(Arg0, Arg1, Arg2, Arg3)); }
void test_case_3() { int Arg0 = 1; int Arr1[] = {}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = {}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 1; int Arg4 = 1; verify_case(3, Arg4, countPaths(Arg0, Arg1, Arg2, Arg3)); }
void test_case_4() { int Arg0 = 4; int Arr1[] = {1,2,3,2,3,3}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = {0,0,0,1,1,2}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 1; int Arg4 = 0; verify_case(4, Arg4, countPaths(Arg0, Arg1, Arg2, Arg3)); }
void test_case_5() { int Arg0 = 4; int Arr1[] = {1,2,3,2,3,3}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = {0,0,0,1,1,2}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 10006; int Arg4 = 33330626; verify_case(5, Arg4, countPaths(Arg0, Arg1, Arg2, Arg3)); }
void test_case_6() { int Arg0 = 14; int Arr1[] = {0,4,0,0,0,12,2,2,9,2,2,3,3,3,3,4,8,4,5,5,10,11,6,12,10,13,10,13,12,13,11}; vector <int> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arr2[] = {2,0,5,8,11,1,5,6,2,10,12,4,5,9,13,7,4,13,6,7,5,5,8,7,8,8,9,9,10,10,13}; vector <int> Arg2(Arr2, Arr2 + (sizeof(Arr2) / sizeof(Arr2[0]))); int Arg3 = 50000; int Arg4 = 372837676; verify_case(6, Arg4, countPaths(Arg0, Arg1, Arg2, Arg3)); }
// END CUT HERE
};
// BEGIN CUT HERE
int main(void) {
HamiltonianPaths ___test;
___test.run_test(-1);
system("pause");
}
// END CUT HERE