HDU - 6416 :Rikka with Seam(DP & 前缀和 & 数学)
pro:给定N*M的矩阵,现在让你在每一行删去一个位置,然后形成新N*(M-1)的矩阵,问有多少种不同的新的矩阵。需要满足相邻行删去的位置不大于K。
(题目是01矩阵,其实任意矩阵都可以做,本题算法里只关心相邻的是否相同。
sol:dp[i][j]表示从上到下删,删到第i行,第i行删去第j列的不同矩阵方案数。
再用一个same数组去重,same[i][j]表示dp[i][j]和dp[i][j-1]的共同部分,即a[i][j]=a[i][j-1]的公共来源部分。
一直维护dp和same数组即可。
详解请移步:https://blog.csdn.net/CatDsy/article/details/81876341
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=2010; const int Mod=998244353; int dp[maxn][maxn],same[maxn][maxn]; int sum1[maxn][maxn],sum2[maxn][maxn]; char c[maxn][maxn]; int main() { int T,N,M,K,ans; scanf("%d",&T); while(T--){ scanf("%d%d%d",&N,&M,&K); rep(i,1,N) scanf("%s",c[i]+1); rep(i,1,M) { dp[1][i]=1; same[1][i]=(i!=1&&c[1][i]==c[1][i-1]); sum1[1][i]=sum1[1][i-1]+dp[1][i]; sum2[1][i]=sum2[1][i-1]+same[1][i]; } rep(i,2,N){ rep(j,1,M) { dp[i][j]=((sum1[i-1][min(M,j+K)]-sum1[i-1][max(0,j-K-1)])%Mod+Mod)%Mod-((sum2[i-1][min(M,j+K)]-sum2[i-1][max(0,j-K)])%Mod+Mod)%Mod; if(dp[i][j]<0) dp[i][j]+=Mod; if(j==1||c[i][j]!=c[i][j-1]) same[i][j]=0; else same[i][j]=((sum1[i-1][min(M,j+K-1)]-sum1[i-1][max(0,j-K-1)])%Mod+Mod)%Mod-((sum2[i-1][min(M,j+K-1)]-sum2[i-1][max(0,j-K)])%Mod+Mod)%Mod; if(same[i][j]<0) same[i][j]+=Mod; sum1[i][j]=(sum1[i][j-1]+dp[i][j])%Mod; sum2[i][j]=(sum2[i][j-1]+same[i][j])%Mod; } } ans=0; rep(i,1,M) ans=((ans+(dp[N][i]-same[N][i])%Mod)%Mod+Mod)%Mod; printf("%d\n",ans); } return 0; }
It is your time to fight!