【插头DP】 ZOJ 3256 Tour in the Castle

通道:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3256

题意:简单路径-左上角走到左下角的路径方案数。

思路:M太大,需快速幂,预处理所有状态即可。

代码:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4
  5 using namespace std;
  6
  7 const int maxn = 10001;
  8 const int MOD = 7777777;
  9 const int mov[10]={0,2,4,6,8,10,12,14,16};
 10
 11 int n, m;
 12 int mp[2 << 16], res[130], tem[130], pos;
 13 bool vd[2 << 16];
 14 int A[6][30][130][130], B[130][130], len[6], sp[6][2];
 15
 16 struct node {
 17     int size, head[maxn], next[maxn], sta[maxn];
 18     inline void clear() {
 19         memset(head, -1, sizeof head);
 20         size = 0;
 21     }
 22     inline void push(int st) {
 23         int hash = st % maxn;
 24         for (int i = head[hash]; ~i; i = next[i]) if (sta[i] == st)
 25             return ;
 26         sta[size] = st; next[size] = hash;
 27         head[hash] = size++;
 28     }
 29 }dp[2];
 30
 31 inline int getbit(int st, int k){return 3 & (st >> mov[k]); }
 32 inline int pybit(int st, int k){return st << mov[k]; }
 33 inline int clrbit(int st, int a, int b){return st & (~(3 << mov[a])) & (~(3 << mov[b])); }
 34
 35 inline int fl(int st, int k, int n) {
 36     int cnt = 1;
 37     for(int i = k + 1; i <= n; ++i) {
 38         int e = getbit(st, i);
 39         if(e == 2) cnt--;
 40         else if(e == 1) cnt++;
 41         if(cnt == 0) return i;
 42     }
 43 }
 44
 45 inline int fr(int st, int k) {
 46     int cnt = 1;
 47     for(int i = k - 1; i >= 0; --i) {
 48         int e = getbit(st, i);
 49         if(e == 2) cnt++;
 50         else if(e == 1) cnt--;
 51         if(cnt == 0) return i;
 52     }
 53 }
 54
 55 inline int find(int st) {
 56     if(mp[st] == -1) mp[st] = pos++;
 57     return mp[st];
 58 }
 59
 60 void bfs(int n) {
 61     queue<int > q;
 62     memset(vd, 0, sizeof vd);
 63     memset(mp, -1, sizeof mp);
 64     memset(B, 0, sizeof B);
 65     pos = 0;
 66     int in = pybit(1, 0) + pybit(2, n - 1);
 67     vd[in] = 1;
 68     q.push(in);
 69     while(!q.empty()) {
 70         int out = q.front(); q.pop();
 71         dp[0].clear();
 72         dp[0].push(out << 2);
 73         int now = 0, pre = 1;
 74         for(int j = 1; j <= n; ++j) {
 75             pre = now, now ^= 1; dp[now].clear();
 76             for (int k = 0; k < dp[pre].size; ++k) {
 77                 int l = getbit(dp[pre].sta[k], j - 1);
 78                 int up = getbit(dp[pre].sta[k], j);
 79                 int st = clrbit(dp[pre].sta[k], j - 1, j);
 80                 if(!l && !up) {
 81                     if(j < n) dp[now].push(st | pybit(1,j-1) | pybit(2,j));
 82                 } else if(!l || !up) {
 83                     int e = l == 0 ? up : l;
 84                     dp[now].push(st | pybit(e, j - 1));
 85                     if(j < n) dp[now].push(st | pybit(e, j));
 86                 } else if(l == 1 && up == 1) dp[now].push(st ^ pybit(3, fl(st, j, n)));
 87                 else if(l == 2 && up == 2) dp[now].push(st ^ pybit(3, fr(st, j - 1)));
 88                 else if(l == 2 && up == 1) dp[now].push(st);
 89                 else if(j == n && st == 0) ++B[find(out)][find(st)];
 90             }
 91         }
 92         for(int j = 0; j < dp[now].size; ++j) {
 93             in = dp[now].sta[j];
 94             if(!vd[in]) {
 95                 vd[in] = 1;
 96                 q.push(in);
 97             }
 98             ++B[find(out)][find(in)];
 99         }
100     }
101 }
102
103 void init() {
104     for (int i = 0; i <= 5; ++i) {
105         bfs(i + 2);
106         len[i] = pos;
107         sp[i][0] = find(pybit(1, 0) + pybit(2, i + 1));
108         sp[i][1] = find(0);
109         for (int j = 0; j < len[i]; ++j)
110             for (int k = 0; k < len[i]; ++k)
111                 A[i][0][j][k] = B[j][k];
112         for (int j = 1; j < 30; ++j) {
113             for (int x = 0; x < len[i]; ++x) {
114                 for (int y = 0; y < len[i]; ++y) {
115                     for (int z = 0; z < len[i]; ++z) {
116                         long long t = (long long)(A[i][j - 1][x][z] * (long long)A[i][j - 1][z][y]);
117                         if(t >= MOD) t %= MOD;
118                         A[i][j][x][y] += t;
119                         if(A[i][j][x][y] >= MOD)  A[i][j][x][y] -= MOD;
120                     }
121                 }
122             }
123         }
124     }
125 }
126
127 void Exp(int k, int e) {
128     int cnt = 0;
129     while(k > 0) {
130         if (k & 1) {
131             for (int j = 0; j < len[e]; ++j) {
132                 tem[j] = 0;
133                 for (int k = 0; k < len[e]; ++k) {
134                     long long t = (long long) res[k] * (long long)A[e][cnt][k][j];
135                     if (t >= MOD) t %= MOD;
136                     tem[j] += t;
137                     if (tem[j] >= MOD) tem[j] -= MOD;
138                 }
139             }
140             memcpy(res, tem, sizeof tem);
141         }
142         k >>= 1; ++cnt;
143     }
144 }
145
146 int main() {
147     init();
148     while (2 == scanf("%d%d", &n, &m)) {
149         memset(res, 0, sizeof res);
150         res[sp[n - 2][0]] = 1;
151         Exp(m, n - 2);
152         if (res[sp[n - 2][1]] == 0) puts("Impossible");
153         else printf("%d\n", res[sp[n - 2][1]]);
154     }
155     return 0;
156 }

时间: 2024-10-29 20:05:15

【插头DP】 ZOJ 3256 Tour in the Castle的相关文章

ZOJ 3256 Tour in the Castle 矩阵快速幂加速

题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3256 题意:给一个n*m的棋盘,求从左上到左下的经过所有格子的方案数 在左边加一列问题就变成了求回路 由于m很大,所以我们需要按列dp 构造出矩阵后,用矩阵快速幂加速 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include&l

插头DP专题

建议入门的人先看cd琦的<基于连通性状态压缩的动态规划问题>.事半功倍. 插头DP其实是比较久以前听说的一个东西,当初是水了几道水题,最近打算温习一下,顺便看下能否入门之类. 插头DP建议先理解“插头”的概念.然后会HASH表(这个其实是很基础的东西,应该都会的).然后就是DP. 以及特殊题目的特殊处理. 好像一般是求N,M<=12的网格图的某种回路数或某种通路数的方案数. 大体上每个题说几句特殊处理,有问题请纠正....题目的顺序基本上难度递增 另外代码我都是用括号匹配的.因为感觉连通

【插头DP】 POJ 1739 Tony&#39;s Tour

通道:http://poj.org/problem?id=1739 题意:左下角走到右下角路径数,单回路.做法就是我们新添2行后寻找回路就可以啦 . 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 7 const int MAX_N = 13; 8 const int MAX_M = 13; 9 const int HASH =

poj 1739 Tony&#39;s Tour 插头dp模板题

题意: 给一个迷宫,求左下角到右下角的路径数. 分析: 插头dp的模板题,建议先看cdq的论文再看代码,这份代码在模板基础上略微有改动.论文地址http://wenku.baidu.com/view/ed2b3e23482fb4daa58d4b74.html 代码: #include <iostream> using namespace std; const int maxD=16; const int HASH=10007; const int STATE=1000024; int N,M;

USACO 6.5 Betsy&#39;s Tour (插头dp)

Betsy's TourDon Piele A square township has been divided up into N2 square plots (1 <= N <= 7). The Farm is located in the upper left plot and the Market is located in the lower left plot. Betsy takes her tour of the township going from Farm to Mark

插头DP小结

首先是CDQ<基于连通性状态压缩的动态规划问题>论文上的题目: URAL 1519 Formula 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 const int maxn = 15; 6 const int HASH = 30007; 7 const int SIZE = 1000010; 8 typedef long lon

[入门向选讲] 插头DP:从零概念到入门 (例题:HDU1693 COGS1283 BZOJ2310 BZOJ2331)

转载请注明原文地址:http://www.cnblogs.com/LadyLex/p/7326874.html 最近搞了一下插头DP的基础知识……这真的是一种很锻炼人的题型…… 每一道题的状态都不一样,并且有不少的分类讨论,让插头DP十分锻炼思维的全面性和严谨性. 下面我们一起来学习插头DP的内容吧! 插头DP主要用来处理一系列基于连通性状态压缩的动态规划问题,处理的具体问题有很多种,并且一般数据规模较小. 由于棋盘有很特殊的结构,使得它可以与“连通性”有很强的联系,因此插头DP最常见的应用要数

插头dp的几个模板

/* ural1519 求经过全部可行点的哈密顿回路的个数 括号匹配法,转移有点复杂,可是时间空间比較小 */ #include<cstdio> #include<cstring> #include<string> #include<iostream> #include<algorithm> #include<cmath> #include<map> #include<queue> #define LL lon

插头dp

对于网格中的dp可以用轮廓线,如果有一些格子不能走就可以用插头dp了. bzoj2331 地板 题目大意:用L型铺地n*m,有一些格子不能铺,求方案数. 思路:fi[i][j][s]表示铺到(i,j),轮廓线状态s,0表示没有插头,1表示插头没拐弯,2表示插头拐弯了,手动枚举转移. 注意:(1)按四进制好写: (2)因为实际状态和四进制的差很多,所以用hash表来存储,防止mle和tle,同时使用滚动数组. #include<iostream> #include<cstdio> #