这题一定要把状态认识清楚,因为只选最后K个点的连通性作为状态,所以一个状态可能会对应很多的连边的情况,由于无法找到特殊的状态吧初始情况地推出来,所以初始情况需要暴力求解,然后再用矩阵加速。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <queue> #include <algorithm> #include <vector> #include <cstring> #include <stack> #include <cctype> #include <utility> #include <map> #include <string> #include <climits> #include <set> #include <string> #include <sstream> #include <utility> #include <ctime> using std::priority_queue; using std::vector; using std::swap; using std::stack; using std::sort; using std::max; using std::min; using std::pair; using std::map; using std::string; using std::cin; using std::cout; using std::set; using std::queue; using std::string; using std::stringstream; using std::make_pair; using std::getline; using std::greater; using std::endl; using std::multimap; using std::deque; typedef long long LL; typedef unsigned long long ULL; typedef pair<int, int> PAIR; typedef multimap<int, int> MMAP; const int MAXN(6010); const int MAXM(5010); const int MAXE(10010); const int HSIZE(13131); const int SIGMA_SIZE(26); const int MAXH(19); const int INFI((INT_MAX-1) >> 1); const ULL BASE(31); const LL LIM(10000000); const int INV(-10000); const int MOD(65521); template<typename T> inline T ABS(const T &op){return op < 0? -op: op;} LL gcd(LL a, LL b) { LL temp; while(b) { temp = a%b; a = b; b = temp; } return a; } LL lcm(LL a, LL b){return a/gcd(a, b)*b;} struct MAT { int r, c; LL arr[60][60]; MAT(int tr, int tc): r(tr), c(tc) { memset(arr, 0, sizeof(arr[0])*r); } MAT() {} void reset() { memset(arr, 0, sizeof(arr[0])*r); } void operator = (const MAT &op) { r = op.r; c = op.c; memcpy(arr, op.arr, sizeof(arr[0])*r); } void identity() { reset(); for(int i = 0; i < r; ++i) arr[i][i] = 1; } }; void mat_mul(const MAT &op1, const MAT &op2, MAT &re) { re.r = op1.r; re.c = op2.c; re.reset(); for(int i = 0; i < op1.c; ++i) for(int j = 0; j < op1.r; ++j) for(int k = 0; k < op2.c; ++k) re.arr[j][k] = (re.arr[j][k]+op1.arr[j][i]*op2.arr[i][k])%MOD; } MAT t1, t2; void mat_pow(const MAT &op, LL n, MAT &re) { t1 = op; re.r = op.r; re.c = op.c; re.identity(); for(int i = 0; (1LL << i) <= n; ++i) { if(n&(1LL << i)) { t2 = re; mat_mul(t1, t2, re); } mat_mul(t1, t1, t2); t1 = t2; } } MAT mat, re, tmat; struct HASH_MAP { int first[HSIZE], next[MAXN]; int state[MAXN]; int value[MAXN]; int size; void init() { memset(first, -1, sizeof(first)); size = 0; } int insert(int ts, int tv) { int h = ts%HSIZE; for(int i = first[h]; ~i; i = next[i]) if(state[i] == ts) { value[i] += tv; return i; } value[size] = tv; state[size] = ts; next[size] = first[h]; first[h] = size; return size++; } } hm1, hm2; int K; int tcode[5], code[5], Num[8]; void decode(int ts) { for(int i = 0; i < K; ++i) { tcode[i] = ts&7; ts >>= 3; } } int encode() { int ret = 0, cnt = 0; memset(Num, -1, sizeof(Num)); for(int i = K-1; i >= 0; --i) { if(Num[code[i]] == -1) Num[code[i]] = cnt++; ret = (ret << 3)|Num[code[i]]; } return ret; } bool vis[5]; void updata() { int cnt = 0; for(int i = 0; i < K; ++i) if(tcode[i] == tcode[0]) ++cnt; int lim = (1 << K)-1; for(int i = 0; i <= lim; ++i) { if(cnt == 1 && (i&1) == 0) continue; memset(vis, 0, sizeof(vis)); bool flag(true); int num = 7; for(int j = 0; j < K; ++j) if(i&(1 << j)) { if(vis[tcode[j]]) { flag = false; break; } num = tcode[j]; vis[tcode[j]] = true; } if(flag) { for(int j = 1; j < K; ++j) code[j-1] = tcode[j]; for(int j = 0; j < K-1; ++j) if(vis[code[j]]) code[j] = num; code[K-1] = num; hm2.insert(encode(), 1); } } } void process(int ind) { hm2.init(); decode(hm1.state[ind]); updata(); for(int i = 0; i < hm2.size; ++i) { int temp = hm1.insert(hm2.state[i], 0); mat.arr[ind][temp] = hm2.value[i]; } } void dfs(int dep) { if(dep == K) { hm1.insert(encode(), 0); return; } for(int i = 0; i <= dep; ++i) { code[dep] = i; dfs(dep+1); } } struct FIND_SET { int fa[5]; void init() { for(int i = 0; i < 5; ++i) fa[i] = i; } int find(int sour){return sour == fa[sour]? sour: fa[sour] = find(fa[sour]);} bool Union(int a, int b) { a = find(a); b = find(b); if(a == b) return false; fa[b] = a; return true; } } fs; int conn[5]; bool closure[5][5]; void dfs2(int dep) //求解初始状态 { if(dep == K) { fs.init(); memset(closure, 0, sizeof(closure)); for(int i = 0; i < K; ++i) { for(int j = i+1; j < K; ++j) if(conn[i]&(1 << (K-1-j))) { if(!fs.Union(i, j)) return; closure[i][j] = true; closure[j][i] = true; } } for(int i = 0; i < K; ++i) for(int j = 0; j < K; ++j) for(int k = 0; k < K; ++k) closure[j][k] |= closure[j][i]&closure[i][k]; int cnt = 0; memset(code, -1, sizeof(code)); for(int i = 0; i < K; ++i) { if(code[i] == -1) code[i] = cnt++; else continue; for(int j = i+1; j < K; ++j) if(closure[i][j]) code[j] = code[i]; } int temp = hm1.insert(encode(), 0); tmat.arr[0][temp] += 1; return; } int lim = (1 << (K-1-dep))-1; for(int i = 0; i <= lim; ++i) { conn[dep] = i; dfs2(dep+1); } } void solve(LL n) { hm1.init(); dfs(0); tmat.r = 1; tmat.c = hm1.size; for(int i = 0; i < hm1.size; ++i) tmat.arr[0][i] = 0; dfs2(0); mat.r = mat.c = hm1.size; mat.reset(); for(int i = 0; i < hm1.size; ++i) process(i); mat_pow(mat, n-K, re); mat_mul(tmat, re, mat); printf("%lld\n", mat.arr[0][0]); } int main() { LL n; while(~scanf("%d%lld", &K, &n)) { solve(n); } return 0; }