以前一直被【jyltxdztysdtgh】吓到,虽然cdq的论文看的懂,但一直没有写,太恶心了。
不过这个时候是必须要写了。
先贴几个链接:
http://www.notonlysuccess.com/index.php/plug_dp/
http://blog.csdn.net/jasonzhu8/article/details/5779518
就小小的总结一下,写【......】的时候让人感觉实在玩接水管游戏,其实只要把各种状态写在纸上,细心一点,多写几遍之后就没那么恶心了。
利用4进制,0表示无括号,1表示左括号,2表示右括号,为了防止写错,就写了两个过程,get(state, p)和cor(state,p,alt),分别是询问state的第p位 / 把state的第p位染成alt,这样每次转移时只用这两个过程,就是的对于一遇到很多运算套在一起就晕(比如我)是一个很大的帮助,虽然会增加代码量,但是为了写对还是值得的。
主要就是要注意细节,换行时的转移,障碍的转移,hash表的处理,只要细节处理好了,就基本上差不多了。
虽然不好调,但是模块化应该还是没有问题的。
ural1519:
模板题,曼哈顿回路个数。
# include <cstdlib> # include <cstdio> # include <cmath> # include <cstring> # include <ctime> using namespace std; const int S = 15000; typedef long long int64; struct HashMap { int top, linke[S*10], next[S*10], point[S*10]; int link(int x, int y) { ++top; next[top] = linke[x]; linke[x] = top; point[top] = y; return top; } int ask(int state) { int ke, hs = state % 10009; for (ke = linke[hs]; ke; ke = next[ke]) if (point[ke] == state) break; return ke? ke: link(hs, state); } }hash; int n, m, head[2], tail[2], que[2][S*10], p; int64 ans, f[2][S*10]; int mat[30], bct[30]; int lastn, lastm; char c[30][30]; bool step[S*10]; inline int get(int state, int pl) { return (state>>((pl-1)<<1))&3; } inline void cor(int &state, int p, int alt) { int pri = get(state, p); state ^= pri << ((p-1)<<1); state |= alt << ((p-1)<<1); } void update(int SX, int x, int y) { f[p][x] += f[!p][y]; if (!step[x]) que[p][++tail[p]] = SX,step[x]=true; } void expand(int state, int line, int list) { //printf("%d\n", state); int i,aim, X, Y, Z, pX, pY; pX = list+1; pY = list+2; X = get(state, pX); Y = get(state, pY); if (c[line][list]=='*'&&(X!=0||get(state,list)!=0)) return; if (list == m) { if (!X) update(state<<2, hash.ask(state<<2),hash.ask(state)); } else if (c[line][list+1] == '*') { if ((!X)&&(!Y)) update(state, hash.ask(state),hash.ask(state)); } else if ((!X) && (!Y)) { aim = state; cor(aim, pX, 1); cor(aim, pY, 2); update(aim, hash.ask(aim),hash.ask(state)); } else if ((!X)||(!Y)) { update(state, hash.ask(state), hash.ask(state)); aim = state; cor(aim, pX, 0); cor(aim, pY, 0); cor(aim, pX, Y); cor(aim, pY, X); update(aim, hash.ask(aim),hash.ask(state)); } else if (X==2 && Y==1) { aim = state; cor(aim, pX, 0); cor(aim, pY, 0); update(aim, hash.ask(aim),hash.ask(state)); } else if (X==Y) { memset(mat,0,sizeof(mat)); memset(bct,0,sizeof(bct)); for (i = 1; i <= m+1; i++) { Z = get(state, i); if (Z==1) mat[++mat[0]] = i; else if (Z==2) bct[i] = mat[mat[0]], bct[mat[mat[0]--]] = i; } aim = state; cor(aim, pX, 0); cor(aim, pY, 0); if (X==1) cor(aim, bct[pY], 1), update(aim, hash.ask(aim),hash.ask(state)); if (X==2) cor(aim, bct[pX], 2), update(aim, hash.ask(aim),hash.ask(state)); } else if (lastn == line && lastm-1 == list) { aim = state; cor(aim, pX, 0); cor(aim, pY, 0); if (!aim)ans += f[!p][hash.ask(state)]; } } void work() { int i, j; que[1][head[1] = tail[1] = 1] = 0; p = 1; f[1][hash.ask(0)] = 1; for (i = 1; i <= n; i++) for (j = 0; j <= m; j++) { p ^= 1; memset(f[p], 0, sizeof(f[p])); head[p] = 1; tail[p] = 0; memset(step, false, sizeof(step)); for (;head[!p] <= tail[!p]; head[!p]++) expand(que[!p][head[!p]], i, j); if (i == lastn && j == lastm) return; } } int main() { int i, j; freopen("ural1519.in", "r", stdin); freopen("ural1519.out", "w", stdout); scanf("%d%d\n", &n, &m); for (i = 1; i <= n; i++) { for (j = 1; j <= m; j++) { scanf("%c", &c[i][j]); if (c[i][j] == '.') lastn = i, lastm = j; } scanf("\n"); } work(); //printf("%d\n", hash.top); printf("%I64d", ans); return 0; }
poj1379:
有限制的曼哈顿路径数量。
仅仅只是对上面的程序改了一点点。
# include <cstdlib> # include <cstdio> # include <cmath> # include <cstring> # include <ctime> using namespace std; const int S = 1000; typedef long long int64; int linke[S], next[S], point[S]; int bct[20], que[2][S], head[2], tail[2], mat[20]; int64 ans, f[2][S]; int n, m, lastn, lastm, X, Y, pX, pY, p; bool step[S]; char c[20][20]; int top; inline int link(int x, int y) { ++top; next[top] = linke[x]; linke[x] = top; point[top] = y; return top; } inline int ask(int state) { int ke , hs = state % 997; for (ke = linke[hs]; ke; ke = next[ke]) if (point[ke] == state) break; return ke? ke:link(hs, state); } inline int get(int state, int pl) { return (state>>((pl-1)<<1))&3; } inline void cor(int &state, int p, int alt) { int tp = get(state, p); state ^= tp << ((p-1)<<1); state ^= alt << ((p-1)<<1); } inline void update(int state, int x, int y) { f[p][x] += f[!p][y]; if (!step[x]) que[p][++tail[p]] = state, step[x] = true; } void expand(int state, int line , int list) { int aim, i, pX = list+1, pY = list+2, X = get(state, pX), Y = get(state, pY); if (list == m) { if (!X) update(state<<2, ask(state<<2), ask(state)); } else if (c[line][list+1] == '#') { if ((!X)&&(!Y)) update(state, ask(state), ask(state)); } else if ((!X)&&(!Y)) { aim = state; cor(aim, pX, 1); cor(aim, pY, 2); update(aim, ask(aim), ask(state)); } else if ((!X)||(!Y)) { aim = state; update(aim, ask(aim), ask(state)); cor(aim, pX, 0); cor(aim, pY, 0); cor(aim, pX, Y); cor(aim, pY, X); update(aim, ask(aim), ask(state)); } else if (X==2&&Y==1) { aim = state; cor (aim, pX, 0); cor(aim, pY, 0); update(aim, ask(aim), ask(state)); } else if (X==Y) { aim = state; memset(bct,0,sizeof(bct)); memset(mat,0,sizeof(mat)); for (i = 1; i <= m+1; i++) { int z = get(state, i); if (z == 1) mat[++mat[0]] = i; else if (z== 2) bct[i] = mat[mat[0]], bct[mat[mat[0]--]] = i; } cor(aim, pX, 0); cor(aim, pY, 0); if (X==1) cor(aim, bct[pY], 1), update(aim, ask(aim), ask(state)); if (X==2) cor(aim, bct[pX], 2), update(aim, ask(aim), ask(state)); } else if (line == lastn && list == lastm-1) { aim = state; cor(aim, pX, 0); cor(aim, pY, 0); if (!aim) ans += f[!p][ask(state)]; } } void origin() { memset(c, sizeof(c), 0); memset(linke, 0, sizeof(linke)); memset(point, 0, sizeof(point)); memset(next, 0, sizeof(next)); top = 0; ans =0; memset(f, 0, sizeof(f)); } void work() { int i, j; int aim = 0; cor(aim, 2, 1); cor(aim, m+1, 2); p = 1; que[p][head[1]=tail[1]=1] = aim; f[p][ask(aim)] = 1; for (i = 1; i <= n; i++) for (j = 0; j <= m; j++) { if (i == lastn&& j == lastm) return; p^=1; memset(f[p], 0, sizeof(f[p])); memset(step, 0, sizeof(step)); head[p] = 1;tail[p] = 0; for (;head[!p]<=tail[!p];head[!p]++) expand(que[!p][head[!p]], i, j); } } int main() { int i, j; //freopen("1739.in", "r", stdin); //freopen("1739.out", "w", stdout); for (;;) { origin(); scanf("%d%d\n", &n, &m); if ((!n)&&(!m)) return 0; for (i = n; i >= 1; i--) { for (j = 1; j <= m; j++) scanf("%c", &c[i][j]); scanf("\n"); } for (i = 1; i <= n; i++) for (j = 1; j <= m; j++) if (c[i][j]=='.') lastn = i, lastm = j; work(); // printf("%d\n", top); if (c[1][1] == '#' || c[1][m] == '#') printf("0\n"); else printf("%I64d\n", ans); } return 0; }
zoj3256
上题 + 矩乘
每次先用按格转移的方式预处理出行与行之间的转移,然后用矩乘优化。
写的很丑很丑。。。。。。在zoj上tle了。。。。。。
# include <cstdlib> # include <cstdio> # include <cmath> # include <cstring> # include <ctime> using namespace std; typedef long long int64; const int mo = 7777777, S = 580; int tot, n, m, p; int bct[30], mat[30], head[2], tail[2], que[2][S+10]; int top, next[S+10], linke[S+10], point[S+10]; int64 f[2][S*5], g[180][180], mtx[180][180], tmp[180][180]; bool step[S*5]; inline int get(int state, int p) { return (state>>((p-1)<<1))&3; } inline void cor(int &state, int p, int alt) { int pri = get(state, p); state ^= pri<<((p-1)<<1); state |= alt<<((p-1)<<1); } inline int link(int x, int y) { ++top; next[top] = linke[x]; linke[x] = top; point[top] = y; //if (top > 200) exit(0); return top; } inline int ask(int state) { int ke,hs = state % 173; for (ke = linke[hs]; ke ; ke = next[ke]) if (point[ke] == state) break; return ke?ke:link(hs, state); } inline bool check(int state) { int i, bt = 0, Z; for (i = 1; i <= n; i++) { Z = get(state, i); if (Z == 1) bt++; else if (Z == 2) bt--; if (bt<0) return false; } return bt?false:true; } inline void update(int st, int x, int y) { int Dx = ask(x);int Dy = ask(y); f[p][Dx] += f[!p][Dy]; if (step[Dx]!=st) step[Dx] = st, que[p][++tail[p]] = x; } void expand(int st, int state, int list) { int i, aim, pX = list+1, pY = list+2, X = get(state, pX), Y = get(state, pY); if (list == n-1 && X == 1 && Y == 2) { aim = state; cor(aim, pX, 0); cor(aim, pY, 0); if (!aim) update(st, aim, state); } else if ((!X)&&(!Y)) { aim = state; cor(aim, pX, 1); cor(aim, pY, 2); update(st, aim, state); } else if ((!X)||(!Y)) { aim = state; update(st, aim, state); cor(aim, pX, Y); cor(aim, pY, X); update(st, aim, state); } else if (X == 2&& Y == 1) { aim = state; cor(aim, pX, 0); cor(aim, pY, 0); update(st, aim, state); } else if (X == Y) { aim = state; cor(aim, pX, 0); cor(aim, pY, 0); memset(bct, 0, sizeof(bct)); memset(mat, 0, sizeof(mat)); for (i = 1; i <= n+1; i++) { int Z = get(state, i); if (Z == 1) mat[++mat[0]] = i; else if (Z == 2) bct[i] = mat[mat[0]], bct[mat[mat[0]--]] = i; } if (X == 1) cor(aim, bct[pY], 1), update(st, aim, state); if (X == 2) cor(aim, bct[pX], 2), update(st, aim, state); } } void work(int state) { int i; p = 1;head[p] = tail[p] = 1; que[1][1] = state; memset(f, 0, sizeof(f)); f[p][ask(state)] = 1; for (i = 0; i < n; i++) { p ^= 1; head[p] = 1; tail[p] = 0; memset(f[p], 0, sizeof(f[p])); memset(step, false, sizeof(step)); for (;head[!p]<= tail[!p];head[!p]++) if (que[!p][head[!p]]!=0) expand(state,que[!p][head[!p]], i); } for (;head[p] <= tail[p];head[p]++) if (get(que[p][head[p]], n+1)==0) mtx[ask(state)][ask(que[p][head[p]]<<2)] += f[p][ask(que[p][head[p]])]; } void dfs(int p, int state) { if (p == 0) {if (check(state)&&(state!=0)) work(state<<2)/*, printf("%d\n", state)*/; return;} dfs(p-1, state<<2); dfs(p-1, (state<<2)+1); dfs(p-1, (state<<2)+2); } void dfsp(int p, int state) { if (p == 0) { if (check(state)) ask(state<<2); return; }; dfsp(p-1, state<<2); dfsp(p-1, (state<<2)+1); dfsp(p-1, (state<<2)+2); } void mul(int64 c[180][180], int64 a[180][180], int64 b[180][180]) { int i, j, k; memset(tmp, 0, sizeof(tmp)); for (i = 1; i <= tot; i++) for (j = 1; j <= tot; j++) for (k = 1; k <= tot; k++) tmp[i][j] = (tmp[i][j] + a[i][k]*b[k][j]) % mo; for (i = 1; i <= tot; i++) for (j = 1; j <= tot; j++) c[i][j] = tmp[i][j]; } void origin() { top = 0; memset(next, 0, sizeof(next)); memset(linke, 0, sizeof(linke)); memset(point, 0, sizeof(point)); memset(g, 0, sizeof(g)); memset(mtx, 0, sizeof(mtx)); } int main() { int i, j; freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout); while (scanf("%d%d", &n, &m)!=EOF) { origin(); dfsp(n,0); tot = top; dfs(n,0); for (i = 1; i <= tot; i++) for (j = 1; j <= tot; j++) g[i][j] = mtx[i][j]; for (m--; m > 0; m>>=1, mul(mtx, mtx, mtx)) if (m&1) mul(g, g, mtx); int aim = 0; cor(aim, 2, 1); cor(aim, n+1, 2); int64 ans = g[ask(aim)][ask(0)]; if (ans) printf("%I64d\n", ans); else printf("Impossible\n"); } return 0; }