1. 程式人生 > >廣場車神 二維字首和優化

廣場車神 二維字首和優化

題目 這一題相信大家都很快可以寫出無優化的DP,我們為了方便DP,換個思路,題目是從左下角出發到右上角,我們改一下,改成從左上角到右下角,我們可以發現這樣是不會對答案有任何影響的。我們定義狀態dp[i][j]表示走到第i行第j個的方案數,狀態轉移方程可想而知:dp[i][j]=以這一格為右下角長度為k+1的正方形內數的累加和,當然超出我們大小的話例如:第2行第2個正方形大小為3,這樣就超了所以我們為了防止陣列越界,DP時要處理一下。下面上60分程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>
using
namespace std; int dp[2010][2010],mod=998244353; int main() { int w,h,k; freopen("racing.in","r",stdin); freopen("racing.out","w",stdout); scanf("%d %d %d",&w,&h,&k); memset(dp,0,sizeof(dp)); dp[1][1]=1; for(int i=1;i<=h;i++)//列舉行 { for(int j=1;j<=w;j++)//列舉列 { for(int p=i;
p<=i+k;p++)//列舉正方形的行 { if(p>h) break; for(int l=j;l<=j+k;l++)//列舉正方形的列 { if(l>w)//防止越界 break; if(p==i && l==j) continue; dp[p][l]=(dp[p][l]+dp[i][j])%mod;//這邊是列舉每個格子然後去更新其他的 } } } } printf("%d",dp[h][w]);//輸出答案 return 0; }

這是60分,我們想想優化,注意我剛剛說的話,我們要求的和是正方形,所以二維字首和才是正解,我們可以邊DP邊做一個二維字首和,一次查詢,這樣就AC了,上程式碼。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int dp[2010][2010],t[2010][2010];
int main()
{
	int w,h,k,mod=998244353;
	scanf("%d %d %d",&w,&h,&k);
	memset(dp,0,sizeof(dp));
	memset(t,0,sizeof(t));
	t[0][0]=1;
	dp[1][1]=1;
	for(int i=1;i<=h;i++)
	{
		for(int j=1;j<=w;j++)
		{
			if(i==1 && j==1)
				continue;
			int x=max(i-k,1),y=max(j-k,1);//處理一下,防止越界 
			t[i][j]=(((t[i-1][j]%mod+t[i][j-1]%mod)%mod)-t[i-1][j-1]%mod+mod)%mod;//我們算一下二維字首和,注意這邊是邊算邊mod,防止計算時溢位,以及減法mod時要注意和加法不同 
			dp[i][j]=(((((((dp[i][j]%mod+t[i][j]%mod)%mod)+t[x-1][y-1]%mod)%mod)-t[i][y-1]%mod+mod)%mod)-t[x-1][j]%mod+mod)%mod;
			t[i][j]=(t[i][j]+dp[i][j]%mod)%mod;//後面還要加一下本格的資料就完美了 
		}
	}
	cout <<dp[h][w];//開心地輸出答案 
	return 0;
}

希望這篇題解對大家有幫助,祝大家早日AC。PS:本程式碼沒有防抄襲,希望大家可以自己打一下,而不要複製黏貼。