1. 程式人生 > >HDU 6416 Rikka with Seam(dp)

HDU 6416 Rikka with Seam(dp)

Description

給出一個n×m01矩陣,要求從每一行刪除一個元素,且相鄰行所刪除元素的列差值不超過K,問刪除後得到的不同矩陣的數量

Input

第一行一整數T表示用例組數,每組用例首先輸入三個整數n,m,K表示矩陣行列數和對列的限制,之後輸入一個n×m01矩陣

(1T103,2n,m2103,1Km)

Output

輸出所得到不同矩陣的數量,結果模998244353

Sample Input

3 2 2 1 00 10 5 5 1 00100 10101 00100 01000 11101 5 5 2 00100 10101 00100 01000 11101

Sample Output

2 70 199

Solution

f[i][j]表示切到(i,j)處對應的不同軌跡數量,則顯然有轉移

f[i][j]=l=max(1,jK)min(m,j+K)f[i1][l] 但是注意到對於一行連續相同的一段數字,刪除任意一個得到的是相同的結果,故直接計算軌跡數量顯然會重,考慮去重,以g[i][j]表示切到(i,j)處所得到的軌跡中與切到(i,j1)處得到的軌跡等價的數量,顯然若s[i][j1]s[i][j]不相同時,到達兩者的軌跡不會等價,考慮s[i][j]=s[i][j1],其相交貢獻區間為[max(1,jK),min(m,j1+K)],那麼有 g[i][j]=l=max(1,jK)min(m,j1+K)f[i1][l]l=max(1,jK)+1min(m,j1+K)g[i1][l]
該樸素dp時間複雜度為O(nm2),注意到都是區間加,故求一遍字首和即可,時間複雜度O(nm)

Code

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
#define maxn 2005
#define mod 998244353
int mul(int x,int y)
{
    ll z=1ll*x*y;
    return z-z/mod*mod;
}
int add(int x,int y)
{
    x+=y;
    if(x>=mod)x-=mod;
    return x;
}
int T,n,m,K,f[maxn][maxn],g[maxn][maxn];
char s[maxn][maxn];
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&K);
        for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                f[i][j]=g[i][j]=0;
        for(int i=1;i<=m;i++)
        {
            f[1][i]=1;
            if(s[1][i]==s[1][i-1])g[1][i]=1;
        }
        for(int i=2;i<=n;i++)
        {
            for(int j=2;j<=m;j++)
            {
                f[i-1][j]=add(f[i-1][j],f[i-1][j-1]);
                g[i-1][j]=add(g[i-1][j],g[i-1][j-1]);
            }
            for(int j=1;j<=m;j++)
            { 
                int L=max(1,j-K),R=min(m,j+K);
                f[i][j]=add(f[i-1][R],mod-f[i-1][L-1]);
                f[i][j]=add(f[i][j],mod-add(g[i-1][R],mod-g[i-1][L]));
                if(s[i][j]!=s[i][j-1])g[i][j]=0;
                else
                {
                    R=min(m,j-1+K);
                    g[i][j]=add(f[i-1][R],mod-f[i-1][L-1]);
                    g[i][j]=add(g[i][j],mod-add(g[i-1][R],mod-g[i-1][L]));
                }
            }
        }
        int ans=0;
        for(int i=1;i<=m;i++)ans=add(ans,add(f[n][i],mod-g[n][i]));
        printf("%d\n",ans);
    }
    return 0;
}