【二维前缀和】

https://nanti.jisuanke.com/t/31434

直接搬题解:

https://www.cnblogs.com/dilthey/p/9757781.html

考虑普通的 dp[i][j]=a=L+1ib=D+1j((a==i&&b==j)?0:dp[a][b])dp[i][j]=∑a=L+1i∑b=D+1j((a==i&&b==j)?0:dp[a][b]),显然就是一整个大方块去掉一小格求和,

其中,D=max(0,ik1)D=max(0,i−k−1) 为下开边界,L=max(0,jk1)L=max(0,j−k−1) 为左开边界,

如果我们老老实实的纯暴力DP,显然就是 O(WHK2)O(WHK2) 的时间复杂度,能过有鬼……

需要使用前缀和优化,不妨假设 sum[i][j]=a=1ib=1jdp[a][b]sum[i][j]=∑a=1i∑b=1jdp[a][b],

那么,显然有状态转移方程 dp[i][j]=(sum[i1][j]+sum[i][j1]sum[i1][j1])(sum[D][j]+sum[i][L]sum[D][L])dp[i][j]=(sum[i−1][j]+sum[i][j−1]−sum[i−1][j−1])−(sum[D][j]+sum[i][L]−sum[D][L]),

进而显然有状态转移方程:

sum[i][j]=(sum[i1][j]+sum[i][j1]sum[i1][j1])+dp[i][j]=2(sum[i1][j]+sum[i][j1]sum[i1][j1])(sum[D][j]+sum[i][L]sum[D][L])sum[i][j]=(sum[i−1][j]+sum[i][j−1]−sum[i−1][j−1])+dp[i][j]=2(sum[i−1][j]+sum[i][j−1]−sum[i−1][j−1])−(sum[D][j]+sum[i][L]−sum[D][L])

最后,易知答案为 dp[h][w]=sum[h][w](sum[h1][j]+sum[i][w1]sum[h1][w1])dp[h][w]=sum[h][w]−(sum[h−1][j]+sum[i][w−1]−sum[h−1][w−1])。

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const ll MOD=998244353;
const int maxn=2000+10;

int w,h,k;
ll sum[maxn][maxn];

int main()
{
scanf("%d%d%d",&w,&h,&k);

memset(sum,0,sizeof(sum));
sum[1][1]=1;
for(int i=1;i<=h;i++)
{
for(int j=1;j<=w;j++)
{
if(i==1&&j==1) continue;
int L=max(0,i-k-1),D=max(0,j-k-1);
sum[i][j]=2*(sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1])-(sum[L][j]+sum[i][D]-sum[L][D]);
while(sum[i][j]<0) sum[i][j]+=MOD; sum[i][j]%=MOD;
}
}
ll ans=sum[h][w]-sum[h-1][w]-sum[h][w-1]+sum[h-1][w-1];
while(ans<0) ans+=MOD; ans%=MOD;
printf("%lld",ans);
}

猜你喜欢

转载自www.cnblogs.com/hgangang/p/11562800.html