HDU 6416 Rikka with Seam(dp)
阿新 • • 發佈:2018-12-09
Description
給出一個的矩陣,要求從每一行刪除一個元素,且相鄰行所刪除元素的列差值不超過,問刪除後得到的不同矩陣的數量
Input
第一行一整數表示用例組數,每組用例首先輸入三個整數表示矩陣行列數和對列的限制,之後輸入一個的矩陣
Output
輸出所得到不同矩陣的數量,結果模
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
令表示切到處對應的不同軌跡數量,則顯然有轉移
但是注意到對於一行連續相同的一段數字,刪除任意一個得到的是相同的結果,故直接計算軌跡數量顯然會重,考慮去重,以表示切到處所得到的軌跡中與切到處得到的軌跡等價的數量,顯然若和不相同時,到達兩者的軌跡不會等價,考慮,其相交貢獻區間為,那麼有 該樸素時間複雜度為,注意到都是區間加,故求一遍字首和即可,時間複雜度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;
}