Tour in the Castle zoj3256

来源:互联网 发布:alt 左键 ubuntu 编辑:程序博客网 时间:2024/06/16 02:04

这题做的很纠结,插头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());}elseif(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());}elseif(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());}elseif(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);elseprintf("Impossible\n");}int main(){while(~scanf("%d%d", &M, &N)){if(M%2 == 1 && N%2 == 0){printf("Impossible\n");continue;}solve();}return 0;}


原创粉丝点击