1. 程式人生 > >JZOJ4019. 【雅禮聯考DAY02】Path

JZOJ4019. 【雅禮聯考DAY02】Path

題意

給定一個 n∗ m 的網格,你在左下角 (n,1),你只能往前走或者右拐,障礙和走過的點不能走。求走到 (y,x) 的方案數 mod k 的值。

資料範圍

n,m ≤ 100,k ≤ 10^9.

Analysis

首先一眼非常不可做,我們畫圖看看,發現它走的路線一定是圈套圈。類似於層層矩形相嵌。此時有想法了,我們考慮對矩形 D P 。設

,i,j,k,l" role="presentation" style="position: relative;"> f p , i , j , k
, l
,表示當前方向為 p ,矩形左上角為 i ,
j
,右下角為 k , l 的方案。
在拐點統計方案,考慮倒著從終點開始做。但是直接統計是 O ( n 5 ) 的,需要在拐點列舉走多少步。考慮每一次拐前的矩形,發現每一次都是少一列,或少一行的矩形。那我們可以考慮矩形構建組合起來。例如 f 0 , i , j , k , l = f 0 , i , j , k , l 1 + f 1 , i + 1 , j , k , l ,考慮路線組合前矩形的形狀。但是空間複雜度爆炸了。
由於每一次矩形行列總和加 1 。所以我們可以列舉行列總和,然後滑動陣列優化空間,就可以通過這道題目。 P . S D P 的初值有點奇妙,不能直接賦值,只有剛好從起點走了一個方向才能賦 1

Code

# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;
const int N = 100 + 5;
char s[N][N];
int f[2][N][N][N][4],h[N][N],li[N][N];
int n,m,x,y,K;
int main()
{
    scanf("%d%d%d",&n,&m,&K);
    scanf("%d%d",&x,&y); swap(x,y);
    for (int i = 1 ; i <= n ; ++i)
        for (int j = 1 ; j <= m ; ++j) scanf(" %c",&s[i][j]);
    for (int i = 1 ; i <= n ; ++i)
        for (int j = 1 ; j <= m ; ++j)
        {
            h[i][j] = h[i - 1][j] + (s[i][j] == '*');
            li[i][j] = li[i][j - 1] + (s[i][j] == '*');
        }
    for (int i = 0 ; i <= n + m - 2 ; ++i)
        for (int j = y ; j >= 1 && y - j <= i ; --j)
            for (int l = y ; l <= m && l - j <= i ; ++l)
                for (int k = x ; k <= n ; ++k)
                {
                    int d = k + l - i - j,s = i & 1,nx = s ^ 1;
                    if (d > x || d < 0) continue;
                    f[s][j][k][l][0] = (l > y) * f[nx][j][k][l - 1][0] + (li[d][j - 1] == li[d][l] && d < x) * f[nx][j][k][l][1];
                    f[s][j][k][l][1] = (k > x) * f[nx][j][k - 1][l][1] + (h[d - 1][l] == h[k][l] && l > y) * f[nx][j][k][l - 1][2];
                    f[s][j][k][l][2] = (j < y) * f[nx][j + 1][k][l][2] + (li[k][j - 1] == li[k][l] && k > x) * f[nx][j][k - 1][l][3];
                    f[s][j][k][l][3] = (d < x) * f[nx][j][k][l][3] + (h[d - 1][j] == h[k][j] && j < y) * f[nx][j + 1][k][l][0];
                    f[s][j][k][l][0] += (d == x && l == y && li[d][j - 1] == li[d][l]);
                    f[s][j][k][l][1] += (k == x && l == y && h[d - 1][l] == h[k][l]);
                    f[s][j][k][l][2] += (k == x && j == y && li[k][j - 1] == li[k][l]);
                    f[s][j][k][l][3] += (d == x && j == y && h[d - 1][j] == h[k][j]);
                    for (int now = 0 ; now < 4 ; ++now) f[s][j][k][l][now] %= K;
                }
    printf("%d\n",f[(n + m - 2) & 1][1][n][m][3]);
    return 0;
}