题面
https://www.lydsy.com/JudgeOnline/problem.php?id=4859
题解
和管道取珠类似
首先把平方转化成两条路径经过的图案相同的方案数
对于一条路径 方向一共有8种 分别是 左上 上 右上 左 右 左下 下 右下 (按照起点和终点的位置关系来确定)
我们枚举两个方向 也就是枚举$8 imes 8$ 一共64种方向 注意到对于方向$(a,b)$ 我们发现有其他3种和它是等价的 分别是$(!a,!b),(b,a),(!b,!a)$ (!a 表示a的反方向) 所以实际上只要做$frac {8 imes 8} {4} =16$种
对于一种情况 我们令$f[a][b][c][d]$表示两条路径的起点分别为$(a,b)$和$(c,d)$的方案数
用记忆化搜索可以算出f数组
然后因为上下左右的四个方向被算了两次 所以得减掉
复杂度$O(16n^4)$
Code
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 ll read(){ 6 ll x=0,f=1;char c=getchar(); 7 while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();} 8 while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();} 9 return x*f; 10 } 11 12 char get(){ 13 char c=getchar(); 14 while(c!='.' && c!='*') c=getchar(); 15 return c; 16 } 17 18 const int mod=1e9+9; 19 int n,m; 20 char s[40][40]; 21 int f[33][33][33][33],g[3][3][3][3]; 22 int dx[3][3][5]={{{-1,-1,0,0,0},{0,0,0,0,0},{1,1,0,0,0}},{{-1,0,0,0,0},{0,0,0,0,0},{1,0,0,0,0}},{{-1,-1,0,0,0},{0,0,0,0,0},{1,1,0,0,0}}},dy[3][3][5]={{{-1,0,-1,0,0},{-1,0,0,0,0},{-1,0,-1,0,0}},{{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}},{{1,0,1,0,0},{1,0,0,0,0},{1,0,1,0,0}}}; 23 24 inline void pl(int &a,int b){a=a+b;if(a>mod) a-=mod;} 25 inline void dec(int &a,int b){a=a-b;if(a<0) a+=mod;} 26 int q,w,e,r; 27 28 int dp(int a,int b,int c,int d){ 29 //cout<<a<<' '<<b<<' '<<c<<' '<<d<<endl; 30 if(s[a][b]!=s[c][d]) return 0; 31 if(a<1 || a>n || b<1 || b>m || c<1 || c>n || d<1 || d>m) return 0; 32 if(f[a][b][c][d]) return f[a][b][c][d]; 33 int sum=1; 34 for(int d1=0;d1<3;d1++){ 35 if(dx[q][w][d1]==0 && dy[q][w][d1]==0) continue; 36 int nwa=a+dx[q][w][d1],nwb=b+dy[q][w][d1]; 37 for(int d2=0;d2<3;d2++){ 38 if(dx[e][r][d2]==0 && dy[e][r][d2]==0) continue; 39 int nwc=c+dx[e][r][d2],nwd=d+dy[e][r][d2]; 40 pl(sum,dp(nwa,nwb,nwc,nwd)); 41 } 42 } 43 return f[a][b][c][d]=sum; 44 } 45 46 int solve(int a,int b,int c,int d){ 47 if(g[a+1][b+1][c+1][d+1]!=0) return g[a+1][b+1][c+1][d+1]; 48 memset(f,0,sizeof(f)); 49 // cout<<a<<' '<<b<<' '<<c<<' '<<d<<endl; 50 q=a+1,w=b+1,e=c+1,r=d+1; 51 int ret=0; 52 for(int i=1;i<=n;i++) 53 for(int j=1;j<=m;j++) 54 for(int x=1;x<=n;x++) 55 for(int y=1;y<=m;y++) 56 pl(ret,dp(i,j,x,y)); 57 g[a+1][b+1][c+1][d+1]=g[c+1][d+1][a+1][b+1]=g[1-a][1-b][1-c][1-d]=g[1-c][1-d][1-a][1-b]=ret; 58 return ret; 59 } 60 61 int solve(int a,int b){ 62 int ans=0; 63 for(int i=-1;i<=1;i++) 64 for(int j=-1;j<=1;j++){ 65 if(i==0 && j==0) continue; 66 if(i==0 || j==0) dec(ans,solve(a,b,i,j)); 67 else pl(ans,solve(a,b,i,j)); 68 } 69 return ans; 70 } 71 72 int main(){ 73 #ifdef LZT 74 freopen("in","r",stdin); 75 freopen("out2","w",stdout); 76 #endif 77 n=read(),m=read(); 78 for(int i=1;i<=n;i++) 79 scanf("%s",s[i]+1); 80 int ans=0; 81 for(int i=-1;i<=1;i++) 82 for(int j=-1;j<=1;j++){ 83 if(i==0 && j==0) continue; 84 if(i==0 || j==0) dec(ans,solve(i,j)); 85 else pl(ans,solve(i,j)); 86 } 87 printf("%d ",ans); 88 return 0; 89 }
Review
1. 注意模数为$10^9+9$ 我一开始写成了$10^9+7$调了半天