这题做的很纠结,插头dp建状态图然后矩阵快速幂求路径条数,一定要把起点和终点设计好,一开始建出来的状态图是对的,但是有很多冗余的状态,自己测了一下,必须TLE,然后又重新设计转移和状态,然后节点个数没有问题了,但是连边又出现问题,样例还是比较厚道的,debug了一下午终于过掉样例, 错误比较隐蔽,已在注释里标出。
#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::istringstream; 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(1000010); const int MAXM(10010); 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 int MOD(7777777); const ULL BASE(31); const LL LIM(10000000); const int INV(-10000); struct MAT { int r, c; LL arr[310][310]; void reset() { for(int i = 0; i < r; ++i) for(int j = 0; j < c; ++j) arr[i][j] = 0; } void identity() { reset(); for(int i = 0; i < r; ++i) arr[i][i] = 1; } MAT &operator =(const MAT &op) { r = op.r; c = op.c; for(int i = 0; i < r; ++i) for(int j = 0; j < c; ++j) arr[i][j] = op.arr[i][j]; return *this; } }; 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]; if(re.arr[j][k] >= MOD) //取模还是很耗时的,不加的话时间是这个的3倍左右 re.arr[j][k] %= MOD; } } MAT t1, t2, *tp1, *tp2, *tre, *temp; void mat_pow(const MAT &op, int n, MAT &re) { t1 = op; re.r = op.r; re.c = op.c; re.identity(); tp1 = &t1; tp2 = &t2; tre = &re; for(int i = 0; (1LL << i) <= n; ++i) { if(n&(1LL << i)) { temp = tp2; tp2 = tre; tre = temp; mat_mul(*tp1, *tp2, *tre); } mat_mul(*tp1, *tp1, *tp2); temp = tp2; tp2 = tp1; tp1 = temp; } re = *tre; } MAT mat, re; void checkmin(int &op1, int op2) {if(op2 < op1) op1 = op2;} struct HASH_MAP { int first[HSIZE], next[MAXN]; int state[MAXN]; int size; void init() { memset(first, -1, sizeof(first)); size = 0; } int insert(int ts) { int h = ts%HSIZE; for(int i = first[h]; ~i; i = next[i]) if(state[i] == ts) { return i; } state[size] = ts; next[size] = first[h]; first[h] = size; return size++; } }hm[2], thm; HASH_MAP *cur, *last; int code[10]; int Num[9]; int N, M; void decode(int ts) { for(int i = 0; i <= M; ++i) { code[i] = ts&7; ts >>= 3; } } int encode() { int ret = 0; int cnt = 0; memset(Num, -1, sizeof(Num)); for(int i = M; i >= 0; --i) if(code[i] == 0) ret <<= 3; else { if(Num[code[i]] < 0) Num[code[i]] = ++cnt; ret = (ret << 3)|Num[code[i]]; } return ret; } void updata(int y) { int up = code[y+1]; int left = (y == 0)? 0: code[y]; if(up == 0 && left == 0) { if(y == M-1) return; code[y] = code[y+1] = 7; cur->insert(encode()); } else if(up == 0 || left == 0) { code[y] = up+left; code[y+1] = 0; cur->insert(encode()); if(y == M-1) return; code[y] = 0; code[y+1] = up+left; cur->insert(encode()); } else if(up != left) { for(int i = 0; i <= M; ++i) if(code[i] == up) code[i] = left; code[y] = code[y+1] = 0; cur->insert(encode()); } else if(y == M-1) { for(int i = 0; i < y; ++i) //一定要注意最后一个格子连接成一条回路时,要确保前几个格子都没有向下(此题是右)的插头,否则会出现非法状态 if(code[i] != 0) return; code[y] = code[y+1] = 0; cur->insert(encode()); } } void process(int ind) { cur = hm; last = hm+1; last->init(); last->insert(thm.state[ind]); for(int i = 0; i < M; ++i) { cur->init(); int sz = last->size; for(int j = 0; j < sz; ++j) { decode(last->state[j]); if(i == 0) for(int k = M; k >= 1; --k) code[k] = code[k-1]; updata(i); } swap(cur, last); } for(int i = 0; i < last->size; ++i) { int temp = thm.insert(last->state[i]); mat.arr[ind][temp] = 1; } } void solve() { memset(mat.arr, 0, sizeof(mat.arr)); thm.init(); for(int i = 0; i <= M; ++i) code[i] = 0; code[0] = 1; code[M-1] = 1; thm.insert(encode()); for(int i = 0; i < thm.size; ++i) //把所有能够转移到的状态求出来 if(thm.state[i] != 0) //注意状态为0的点不可以再转移,否则会出现冗余状态 process(i); mat.r = mat.c = thm.size; mat_pow(mat, N, re); LL ans = 0; for(int i = 0; i < thm.size; ++i) if(thm.state[i] == 0) { ans = re.arr[0][i]; break; } if(ans) printf("%lld\n", ans); else printf("Impossible\n"); } int main() { while(~scanf("%d%d", &M, &N)) { if(M%2 == 1 && N%2 == 0) { printf("Impossible\n"); continue; } solve(); } return 0; }