BZOJ1126: [POI2008]Uci

138 篇文章 0 订阅
77 篇文章 0 订阅

因为出发点是在左下角,每次只能右转,所以走的一定是个顺时针,不能走已走过的位置限制了剩余能走的区域一定是个矩形
f[l][r][d][u][0 to 3] 表示当前能走的矩形区域的四条边的位置和当前的方向,因为矩形确定了,方向确定了,当前位置其实也就确定了所以不用记录当前位置
数组开不下这么大,但注意到按照dp的顺序,l是递增的,可以滚动掉这一维
转移时每次走一次走到转向,维护4个方向的前缀和,预处理每个位置4个方向第一个障碍

感觉很不好写呀qwq

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

const int maxn = 105;
int mod;
inline void add(int &a,int b){a+=b;if(a>=mod)a-=mod;}
inline void dec(int &a,int b){a-=b;if(a<0)a+=mod;}

int n,m,edx,edy;
int ok[maxn][maxn];
char str[maxn];

int To[maxn][maxn][4];
void preto()
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            To[i][j][3]=To[i][j-1][3];
            if(!ok[i][j]) To[i][j][3]=j;
        }
        To[i][m+1][1]=m+1;
        for(int j=m;j>=1;j--)
        {
            To[i][j][1]=To[i][j+1][1];
            if(!ok[i][j]) To[i][j][1]=j;
        }
    }
    for(int j=1;j<=m;j++)
    {
        To[n+1][j][2]=n+1; if(j==1) To[n+1][j][2]=n+2;
        for(int i=n;i>=1;i--)
        {
            To[i][j][2]=To[i+1][j][2];
            if(!ok[i][j]) To[i][j][2]=i;
        }
        for(int i=1;i<=n;i++)
        {
            To[i][j][0]=To[i-1][j][0];
            if(!ok[i][j]) To[i][j][0]=i;
        }
    }
}
// 0 up
// 1 right
// 2 down
// 3 left
int f[2][maxn][maxn][maxn][4];
int sum[maxn][maxn][maxn];
int s[maxn][maxn][maxn][4];
int re;

int main()
{
    scanf("%d%d%d",&n,&m,&mod);
    scanf("%d%d",&edx,&edy);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",str+1);
        for(int j=1;j<=m;j++) ok[i][j]=(str[j]=='+');
    }
    preto();
    if(edx==1) return printf("%d\n",To[edy][edx][2]<=n?0:1),0;

    int now=0;
    for(int d=1;d<=n;d++) s[m][d][n][0]=1;
    for(int l=2;l<=edx+1;l++)
    {
        now=!now;
        for(int r=m;r>=l-1;r--) for(int d=1;d<=n;d++) for(int u=d;u<=n;u++) 
        {
            s[r][d][u][1]=s[r+1][d][u][1];
            int &tmp=f[now][r][d][u][1]; tmp=0;
            if(To[d][l-1][2]>u+1)
            {
                tmp=s[r][d][u][0];
                add(s[r][d][u][1],tmp);

                if(l-1==edx&&d==edy) add(re,tmp);
            }
        }
        for(int r=l;r<=m;r++) for(int d=2;d<=n+1;d++) for(int u=n;u>=d-1;u--) 
        {
            s[r][d][u][2]=s[r][d][u+1][2];
            int &tmp=f[now][r][d][u][2]; tmp=0;
            if(To[d-1][r][3]<l-1)
            {
                tmp=s[r][d-1][u][1];
                add(s[r][d][u][2],tmp);

                if(r==edx&&d-1==edy) add(re,tmp);
            }
        }
        for(int r=l-1;r<=m-1;r++) for(int d=1;d<=n;d++) for(int u=d;u<=n;u++) 
        {
            int &tmp=f[now][r][d][u][3]; tmp=0;
            if(To[u][r+1][0]<d-1)
            {
                tmp=s[r+1][d][u][2];
                add(sum[r][d][u],tmp);

                if(r+1==edx&&u==edy) add(re,tmp);
            }
        }
        for(int r=l;r<m;r++) for(int d=1;d<=n;d++) for(int u=d-1;u<=n-1;u++) 
        {
            s[r][d][u][0]=s[r][d-1][u][0];
            int &tmp=f[now][r][d][u][0]; tmp=0;
            if(To[u+1][l][1]>r+1)
            {
                tmp=sum[r][d][u+1];
                add(s[r][d][u][0],tmp);

                if(l==edx&&u+1==edy) add(re,tmp);
            }
        }
    }
    printf("%d\n",re);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值