2018多校第九场 HDU 6416 (DP+前缀和优化)
转自:https://blog.csdn.net/CatDsy/article/details/81876341
#include <bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long #define mst(a,b) memset((a),(b),sizeof(a)) #define pi acos(-1) #define pii pair<int,int> const int INF = 0x3f3f3f3f; const double eps = 1e-6; const int MAXN = 2e3 + 10; const int MAXM = 2e6 + 10; const ll mod = 998244353; char s[MAXN][MAXN]; ll tot[MAXN][MAXN], same[MAXN][MAXN]; ll pre_tot[MAXN][MAXN], pre_same[MAXN][MAXN]; int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif int t; scanf("%d",&t); while(t--) { int n,m,k; 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++) pre_tot[i][0] = pre_same[i][0] = 0; for(int i = 1; i <= m; i++) { tot[1][i] = 1; pre_tot[1][i] = i; if(i == 1 || s[1][i] != s[1][i - 1]) same[1][i] = 0; else same[1][i] = 1; pre_same[1][i] = pre_same[1][i - 1] + same[1][i]; } for(int i = 2; i <= n; i++) { for(int j = 1; j <= m; j++) { int l = max(j - k, 1), r = min(j + k, m); tot[i][j] = (pre_tot[i - 1][r] - pre_tot[i - 1][l - 1] + mod) % mod; l = max(j - k + 1, 1), r = min(j + k, m); tot[i][j] = (tot[i][j] - (pre_same[i - 1][r] - pre_same[i - 1][l - 1] + mod) % mod + mod) % mod; pre_tot[i][j] = (pre_tot[i][j - 1] + tot[i][j]) % mod; if(j == 1 || s[i][j] != s[i][j - 1]) same[i][j] = 0; else { l = max(j - k, 1), r = min(j + k - 1, m); same[i][j] = (pre_tot[i - 1][r] - pre_tot[i - 1][l - 1] + mod) % mod; l = max(j - k + 1, 1), r = min(j + k - 1, m); same[i][j] = (same[i][j] - (pre_same[i - 1][r] - pre_same[i - 1][l - 1] + mod) % mod + mod) % mod; } pre_same[i][j] = (pre_same[i][j - 1] + same[i][j]) % mod; } } ll ans = 0; for(int i = 1; i <= m; i++) ans = (ans + tot[n][i] - same[n][i] + mod) % mod; printf("%lld\n",ans); } return 0; }
题目描述:
给定一个N∗M的01矩阵
K-seam是满足以下条件的整数序列a:
- |a|=n,ai∈[1,m]
- |ai−ai+1|≤K,i∈[1,n)
对于第i行,删除第ai个数,会得到一个N∗(M−1)的矩阵
不同的整数序列可能会得到相同的矩阵
问:可以得到多少种不同的矩阵
题解:
如果无视different的条件
定义状态:dp[i][j]——删除第 i 行第 j 个数可以得到的矩阵总数
可推得转移方程如下:
dp[i][j]=∑x=j−kj+kdp[i−1][x]
在此基础上,加上different的条件
定义状态:
- tot[i][j]——删除第 i 行第 j 个数可以得到的不同的矩阵总数
- same[i][j]——删除第 i 行第 j 个数和删除第 i 行第 j−1 个数后得到的相同方案数
那么,tot[i][j]的状态转移方程为:
tot[i][j]=∑x=j−kj+ktot[i−1][x]−∑x=j−k+1j+ksame[i−1][x]
如果 Matrix[i][j]≠Matrix[i][j−1] 那么,same[i][j]=0
否则,对于第 j 个和第 j−1 个的转移区间分别为[j−k,j+k],[j−1−k,j−1+k],那么它们的交叉区间为[j−k,j−1+k],即:从该区间内转移得到的方案数会重复计算一次。得到 same[i][j] 的转移方程为:
same[i][j]=∑x=j−kj+k−1tot[i−1][x]−∑x=j−k+1j+k−1same[i−1][x]
时间复杂度为O(n∗m2),对于∑做前缀和优化,时间复杂度降为O(n∗m)
最后,对于第n行计算总的不同的方案数,即ans=∑tot−∑same