这题一定要把状态认识清楚,因为只选最后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;
}