只能走补图的边
那么原图色的边不能走
那么我们容斥走了几条原图的边
这些边肯定是一些链
把链缩成一个点 那么不考虑其他不合法边用不用的情况下 贡献是 m的阶乘
m是缩完够的点数
然后 因为缩起来的点只可能是在同一个模板图中
那么对于最后总点数m的缩点方案数 是可以先处理出单个模板图的方案数 然后fft的
状压dp预处理模板图
// BEGIN CUT HERE
#include
#include
// END CUT HERE
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
const int N=1200005;
const int P=998244353;
inline ll Pow(ll a,int b){
ll ret=1;
for (;b;b>>=1,a=a*a%P)
if (b&1)
ret=ret*a%P;
return ret;
}
int num;
int w[2][N];
int R[N];
inline void Pre(int m){
num=m; ll g=Pow(3,(P-1)/m);
w[0][0]=w[1][0]=1;
for (int i=1;i1][i]=w[1][i-1]*g%P;
for (int i=1;i0][i]=w[1][m-i];
int L=0,t=m; while (t>>=1) L++;
for (int i=1;i>1]>>1)|((i&1)<<(L-1));
}
inline void FFT(int *a,int n,int r){
for (int i=0;iif (R[i]for (int i=1;i1)
for (int j=0;j1))
for (int k=0;kint x=a[j+k],y=(ll)a[j+i+k]*w[r][num/(i<<1)*k]%P;
a[j+k]=(x+y)%P,a[j+i+k]=(x+P-y)%P;
}
if (!r) for (int i=0,inv=Pow(n,P-2);iconst int KK=14;
struct edge{
int u,v,next;
}G[KK*KK+5];
#define V G[p].v
int head[KK+5],inum;
inline void add(int u,int v,int p){
G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
int n,m,K;
int f[1<5],F[1<int g[1<5];
inline void add(int &x,int y){
x+=y; if (x>=P) x-=P;
}
int a[N];
class HamiltonianPaths{
public:
int countPaths(int _k, vector <int> _a, vector <int> _b, int _n){
K=_k; n=_n; m=_a.size();
for (int i=1;i<=m;i++) add(_a[i-1]+1,_b[i-1]+1,++inum),add(_b[i-1]+1,_a[i-1]+1,++inum);
for (int i=1;i<=K;i++) f[1<<(i-1)][i]=1;
for (int i=1;i<(1<for (int j=1;j<=K;j++)
if ((i>>(j-1)&1) && f[i][j]){
for (int p=head[j];p;p=G[p].next)
if (!(i>>(V-1)&1))
add(f[i|(1<<(V-1))][V],f[i][j]);
}
for (int i=1;i<(1<for (int j=1;j<=K;j++)
add(F[i],f[i][j]);
g[0][0]=1;
for (int i=1;i<(1<for (int j=1;j<=K;j++)
for (int k=i;k;k=(--k)&i)
add(g[i][j],(ll)g[i^k][j-1]*F[k]%P);
int m=1; while (m<=n*K) m<<=1; Pre(m);
ll fac=1;
for (int i=1;i<=K;i++,fac=fac*i%P)
a[i]=(ll)g[(1<1][i]*Pow(fac,P-2)%P;
FFT(a,m,1);
for (int i=0;i0);
ll ans=0; fac=1;
for (int i=1;i<=n*K;i++,fac=fac*i%P)
if ((n*K-i)&1)
ans+=P-fac*a[i]%P;
else
ans+=fac*a[i]%P;
return ans%P;
}
// 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 &_V) { ostringstream os; os << "{ "; for (typename vector ::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(int argc,char* argv[]){
HamiltonianPaths ___test; int tt;
scanf("%d",&tt);
___test.run_test(tt);
getch() ;
return 0;
}
// END CUT HERE