正题
题目链接:https://jzoj.net/senior/#contest/show/3014/1
题目大意
n∗mn*mn∗m的格子,开始在(n,1)(n,1)(n,1),每次可以右拐或者往前,不能走重复的和障碍,求有多少种方案到达(y,x)(y,x)(y,x)
解题思路
设fs,x1,y1,x2,y2f_{s,x1,y1,x2,y2}fs,x1,y1,x2,y2表示目前朝向为sss,先前所走的范围都在(x1,y1,x2,y1)(x1,y1,x2,y1)(x1,y1,x2,y1)这个矩形内的方案数。
要滚动,我们枚举iii表示这个矩形 长+宽=iii 然后进行dpdpdp即可。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define star(x,y) ((x)==sx&&(y)==sy)
using namespace std;
const ll N=101;
const ll dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
ll n,m,sx,sy,p,f[2][4][N][N][N],ans;
ll v1[N][N],v2[N][N];
char s[N];
int main()
{scanf("%lld%lld%lld",&n,&m,&p);scanf("%lld%lld",&sy,&sx);for(ll i=1;i<=n;i++){scanf("%s",s+1);for(ll j=1;j<=m;j++){v1[i][j]=v1[i][j-1]+(s[j]=='*');v2[i][j]=v2[i-1][j]+(s[j]=='*');}}for(ll i=2;i<=n+m;i++){for(ll x=1;x<i;x++){ll y=i-x;for(ll h=1;h<=sx&&x+h-1<=n;h++)for(ll w=1;w<=sy&&y+w-1<=m;w++){ll zx=x+h-1,zy=y+w-1;if(zx<sx||zy<sy) continue;f[i&1][0][h][w][zx]=(f[~i&1][0][h][w][zx]+(v1[h][zy]-v1[h][w-1]==0)*(f[~i&1][1][h+1][w][zx]+star(h,zy)))%p;f[i&1][1][h][w][zx]=(f[~i&1][1][h][w][zx-1]+(v2[zx][zy]-v2[h-1][zy]==0)*(f[~i&1][2][h][w][zx]+star(zx,zy)))%p;f[i&1][2][h][w][zx]=(f[~i&1][2][h][w+1][zx]+(v1[zx][zy]-v1[zx][w-1]==0)*(f[~i&1][3][h][w][zx-1]+star(zx,w)))%p;f[i&1][3][h][w][zx]=(f[~i&1][3][h+1][w][zx]+(v2[zx][w]-v2[h-1][w]==0)*(f[~i&1][0][h][w+1][zx]+star(h,w)))%p;} }}printf("%lld",f[(n+m)&1][3][1][1][n]);return 0;
}