P3713 [BJOI2017] 机动训练
P3713 [BJOI2017] 机动训练
题目背景
AM 4:45
又是晴朗的好天气。
AM 5:00
不要嘛,再睡一会
AM 5:05
呜……欺负人
题目描述
睡眼朦胧的菜酱 (?) 已经被二爷拉起来晨跑了。而这个时间你在做什么呢?
咳咳,言归正传,最近菜酱的训练遇到了点小麻烦。
凌晨绕格瑞赛亚岛跑一圈是基本,在那之后,菜酱还要接受严格的机动训练。所谓机动训练,就是在紧急情况 (?) 下,高速且隐蔽地从位置
一次偶然的机会,菜酱看到了二爷的随机策略,并发动技能「过目不忘 (?)」记了下来。现在你要帮菜酱分析数据。
为什么是你?当然是因为否则就会被菜酱爆头 (并不)。
整个岛可以看作一片
一条路径由一系列八连通的格子组成,两个格子八连通当且仅当这两个格子拥有公共的顶点。
定义一条“机动路径”如下:
- 它是一条不自交的路径,即路径上任意两个格子都不是同一个。
- 它的起点和终点处于不同位置,换言之这条路径至少包含
个格子。 - 从起点开始,任何一步只能向不远离终点的方向移动,这里不远离指的是
和 两个方向都不远离。
举例说明:
.....t ...... .---. -++... ---... .-s-. -s+... -s+..t .-+-. ---... ---... ..t..
图中加号和减号标明了与
因此可以看出,如下路径是机动路径:
++++++t ......+t .......t +...... .....++. ......+. +...... ..++++.. ...+++.. s...... s++..... s+++....
而如下路径不是机动路径:
\../---t .......t .s. |--..... ....../. /.. |....... s..../.. \.. s....... .\--/... .t.
需要注意的是,某些不合法的路径甚至比机动路径还要短,这是因为机动路径不是按照长度来定义的。
接下来定义一条机动路径的地形,岛上的地形由一个矩阵给出,如:
.**. *..* *..* .**.
那么,一条机动路径的地形序列就是它所经过的地形排成一列,如:
s-\. ...\ ...| ...t
地形序列就是 .****.
。
每条机动路径的权重就是与之拥有相同地形序列的机动路径数量之和,例如与这条路径拥有相同地形序列的路径有
./-t t... ...s s-\. ./-s s... ...t t-\. /... |... ...| ...\ /... |... ...| ...\ |... \... .../ ...| |... \... .../ ...| s... .\-s t-/. ...t t... .\-t s-/. ...s
共
所以这条机动路径的权重是
现在你需要统计所有的机动路径权重之和。
如果对这种统计方式没有直观的感受,可以查看样例说明。
输入格式
第一行两个整数
接下来
输出格式
仅一个数,表示所有机动路径的权重之和。
由于这个数可能很大,你只需要输出它对
样例 #1
样例输入 #1
2 2 .* *.
样例输出 #1
72
样例 #2
样例输入 #2
2 3 .*. *.*
样例输出 #2
418
提示
样例解释 1
用中括号括起来的一些数对表示一条机动路径,坐标先行后列:
- 地形序列
.*
: ,共 条,每条权重为 ,计 。 - 地形序列
*.
: ,共 条,每条权重为 ,计 。 - 地形序列
..
: ,共 条,每条权重为 ,计 。 - 地形序列
**
: ,共 条,每条权重为 ,计 。 - 地形序列
.*.
: ,共 条,每条权重为 ,计 。 - 地形序列
*.*
: ,共 条,每条权重为 ,计 。
共计
样例解释 2
- 地形序列
.*
: 条,每条权重为 ,计 。 - 地形序列
*.
: 条,每条权重为 ,计 。 - 地形序列
..
: 条,每条权重为 ,计 。 - 地形序列
**
: 条,每条权重为 ,计 。 - 地形序列
..*
: 条,每条权重为 ,计 。 - 地形序列
.*.
: 条,每条权重为 ,计 。 - 地形序列
.**
: 条,每条权重为 ,计 。 - 地形序列
*..
: 条,每条权重为 ,计 。 - 地形序列
*.*
: 条,每条权重为 ,计 。 - 地形序列
**.
: 条,每条权重为 ,计 。 - 地形序列
.*.*
: 条,每条权重为 ,计 。 - 地形序列
*.*.
: 条,每条权重为 ,计 。
共计
- 对于
的数据, ,字符集由大小写字母,数字和.
*
构成。
Sulution:
这应该是我为数不多没删样例及其解释的题目,因为真的很有用。
首先,题目要求的路径的起点和终点竟然是任意的,然后我们来看一下让我们求什么:对于个序列,假设它被“走出”过
然后我们发现点的个数
然后我们就可以钦定一个方向对
Code:
#include<bits/stdc++.h> #define int long long const int N=35; const int mod=1000000009; using namespace std; int n,m; char Map[N][N]; int f[N][N][N][N]; int g[5][5][5][5]; void init(){for(int i=0;i<N;i++)for(int j=0;j<N;j++)for(int p=0;p<N;p++)for(int q=0;q<N;q++)f[i][j][p][q]=-1;} struct Node{int dx,dy;}; void add(int &x,int y){x=(x+y)%mod;} vector<Node> A,B; void build_way(int a,int b,vector<Node> &V) { V.clear(); for(int i=-1;i<=1;i++)if(!i||i==a)for(int j=-1;j<=1;j++)if((i||j)&&(!j||j==b))V.push_back((Node){i,j}); } int dp(int a,int b,int c,int d) { if(a<1||n<a||b<1||m<b)return 0; if(c<1||n<c||d<1||m<d)return 0; if(Map[a][b]!=Map[c][d]) return f[a][b][c][d]=0; if(~f[a][b][c][d])return f[a][b][c][d]; int aa,bb,cc,dd; int res=1; for(Node d1 : A)for(Node d2 : B) { aa=a+d1.dx,bb=b+d1.dy,cc=c+d2.dx,dd=d+d2.dy; add(res,dp(aa,bb,cc,dd)); } return f[a][b][c][d]=res; } int dfs(int a,int b,int c,int d) { int aa=a+1,bb=b+1,cc=c+1,dd=d+1; int _a=-a+1,_b=-b+1,_c=-c+1,_d=-d+1; if(~g[aa][bb][cc][dd])return g[aa][bb][cc][dd]; build_way(a,b,A);build_way(c,d,B); init(); int res=0; for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)for(int p=1;p<=n;p++)for(int q=1;q<=m;q++) { add(res,dp(i,j,p,q)); } g[aa][bb][cc][dd]=g[cc][dd][aa][bb]=res; g[_a][_b][_c][_d]=g[_c][_d][_a][_b]=res; return res; } vector<Node> Way1,Way2; void build() { for(int i=-1;i<=1;i++)for(int j=-1;j<=1;j++) if(i&&j)Way2.push_back((Node){i,j});else if(i||j)Way1.push_back((Node){i,j}); } int calc(int x,int y) { int res=0; for(Node d : Way2)add(res,dfs(x,y,d.dx,d.dy)); for(Node d : Way1)add(res,-dfs(x,y,d.dx,d.dy)+mod); return res; } void work() { cin>>n>>m; memset(g,-1,sizeof(g)); build(); for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)cin>>Map[i][j]; int ans=0; for(Node d : Way2)add(ans,calc(d.dx,d.dy)); for(Node d : Way1)add(ans,-calc(d.dx,d.dy)+mod); printf("%lld\n",ans); } #undef int int main() { //freopen("makina.in","r",stdin);freopen("makina.out","w",stdout); ios_base::sync_with_stdio(0); cin.tie(0); work(); return 0; }