P3713 [BJOI2017]机动训练
这个题简直神仙,求相同路径的平方就等于两个人走相同路径的方案数。然后。。。暴力搜索+记忆化就行了,比较玄学。
题干:
题目描述 整个岛可以看作一片 n*m 的区域,每个格子有自己的地形。 一条路径由一系列八连通的格子组成,两个格子八连通当且仅当这两个格子拥有公共的 顶点。 定义一条“机动路径”如下: 1、它是一条不自交的路径,即路径上任意两个格子都不是同一个 2、它的起点和终点处于不同位置,换言之这条路径至少包含 2 个格子 3、从起点开始,任何一步只能向不远离终点的方向移动,这里不远离指的是 x 和 y 两 个方向都不远离 举例说明(字符画需要用等宽字体查看): .....y ...... .---. -++... ---... .-x-. -x+... -x+..y .-+-. ---... ---... ..y.. 图中加号和减号标明了与 x 八连通的所有格子,其中加号是“不远离 y”的方向 因此可以看出,如下路径是机动路径: ++++++y ......+y .......y +...... .....++. ......+. +...... ..++++.. ...+++.. x...... x++..... x+++.... 而如下路径不是机动路径: \../---y .......y .x. |--..... ....../. /.. |....... x..../.. \.. x....... .\--/... .y. 需要注意的是,某些不合法的路径甚至比机动路径还要短,这是因为机动路径不是按照 长度来定义的。 接下来定义一条机动路径的地形,岛上的地形由一个矩阵给出,如 .**. *..* *..* .**. 那么,一条机动路径的地形序列就是它所经过的地形排成一列,如 x-\. ...\ ...| ...y 的地形序列就是".****."(不包含引号) 每条机动路径的权重就是与之拥有相同地形序列的机动路径数量之和,例如与这条路径 拥有相同地形序列的路径有 ./-y y... ...x x-\. ./-x x... ...y y-\. /... |... ...| ...\ /... |... ...| ...\ |... \... .../ ...| |... \... .../ ...| x... .\-x y-/. ...y y... .\-y x-/. ...x 共 8 条,注意回文时正反算两条,以及自己也算一条。 所以这条机动路径的权重是 8,同时所有这 8 条机动路径的权重都是 8。 现在你需要统计所有的机动路径权重之和。 如果对这种统计方式没有直观的感受,可以查看样例说明。
代码:
#include<iostream> #include<cstdio> #include<cmath> #include<ctime> #include<queue> #include<algorithm> #include<cstring> using namespace std; #define duke(i,a,n) for(register int i = a;i <= n;++i) #define lv(i,a,n) for(register int i = a;i >= n;--i) #define clean(a) memset(a,0,sizeof(a)) const int INF = 1 << 30; typedef long long ll; typedef double db; template <class T> void read(T &x) { char c; bool op = 0; while(c = getchar(), c < '0' || c > '9') if(c == '-') op = 1; x = c - '0'; while(c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; if(op) x = -x; } template <class T> void write(T x) { if(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar('0' + x % 10); } const int N = 31,mod = 1000000009; int n,m,f[N][N][N][N],g[3][3][3][3],ans; int dx[4],dy[4],dp[4],dq[4],tp1,tp2; char str[N][N]; int DP(int x,int y,int p,int q) { if(str[x][y] != str[p][q]) return 0; if(x < 1 || x > n || y < 1 || y > m) return 0; if(p < 1 || p > n || q < 1 || q > m) return 0; if(f[x][y][p][q] != -1) return f[x][y][p][q]; int res = 1; duke(i,1,tp1) { duke(j,1,tp2) { res = (res + DP(x + dx[i],y + dy[i],p + dp[j],q + dq[j])) % mod; } } return f[x][y][p][q] = res; } int Calc(int x,int y,int p,int q) { if(g[x + 1][y + 1][p + 1][q + 1] != -1) return g[x + 1][y + 1][p + 1][q + 1]; tp1 = 0; duke(i,-1,1) { if(!i || i == x) { duke(j,-1,1) { if((i || j) && (!j || j == y)) { tp1++; dx[tp1] = i; dy[tp1] = j; } } } } tp2 = 0; duke(i,-1,1) { if(!i || i == p) { duke(j,-1,1) { if((i || j) && (!j || j == q)) { tp2++; dp[tp2] = i; dq[tp2] = j; } } } } int res = 0; memset(f,-1,sizeof(f)); duke(i,1,n) { duke(j,1,m) { duke(k,1,n) { duke(l,1,m) { res = (res + DP(i,j,k,l)) % mod; } } } } g[x + 1][y + 1][p + 1][q + 1] = res; g[p + 1][q + 1][x + 1][y + 1] = res; g[-x + 1][-y + 1][-p + 1][-q + 1] = res; g[-p + 1][-q + 1][-x + 1][-y + 1] = res; return res; } int calc(int x,int y) { int res = 0; res = (res + Calc(x,y,1,1)) % mod; res = (res + Calc(x,y,1,-1)) % mod; res = (res + Calc(x,y,-1,1)) % mod; res = (res + Calc(x,y,-1,-1)) % mod; res = (res - Calc(x,y,1,0) + mod) % mod; res = (res - Calc(x,y,-1,0) + mod) % mod; res = (res - Calc(x,y,0,1) + mod) % mod; res = (res - Calc(x,y,0,-1) + mod) % mod; return res; } int main() { read(n);read(m); duke(i,1,n) { scanf("%s",str[i] + 1); } memset(g,-1,sizeof(g)); ans = (ans + calc(1,1)) % mod; ans = (ans + calc(1,-1)) % mod; ans = (ans + calc(-1,1)) % mod; ans = (ans + calc(-1,-1)) % mod; ans = (ans - calc(1,0) + mod) % mod; ans = (ans - calc(-1,0) + mod) % mod; ans = (ans - calc(0,1) + mod) % mod; ans = (ans - calc(0,-1) + mod) % mod; printf("%d\n",ans); return 0; }
只想找一个不会伤害我的人