CF295D - Greg and Caves 题解

Portal

我们考虑将整个洞分成两半,一半递增,一半递减。我们分别 DP 求值,最后合并。

显然上下半是对称的。。我们考虑 \(dp_{i,l,r}\) 表示前 \(i\) 行递增,第 \(i\) 行区间为 \(l,r\) 的方案数。然后你发现这个空间就炸了。进一步发现,\(r-l+1\) 相等的一些 \([l,r]\) 是等价的,于是我们只记录区间长度。于是 \(dp_{i,j}\)

转移方程(上面空和不空,不空枚举长度):

\[dp_{i,j}=\sum_{k=2}^j(j-k+1)dp_{i-1,k}+1 \]

直接算是三方的,考虑将 \(j-k+1\) 拆开得到 \(j+1\)\(-k\)。那么我们只需要维护 \(dp_{i,j}\) 的前缀和,和 \(-j\cdot dp_{i,j}\) 的前缀和即可平方。

然后我们要做的是求答案。考虑枚举最长的那行和那行的长度,平方?你会发现有重复,因为最长的那行后可能有多个。那怎么办呢?注意到它们长得像一个火箭筒一样,我们枚举极大最长行区间 instead of 最长行。那这样就是三方的了啊。为了优化,我们把式子写出来然后推。

\[\begin{aligned}ans&=\sum_{i=1}^n\sum_{j=i}^n\sum_{k=2}^m(dp_{i,k}-dp_{i-1,k})(dp_{n-j+1,k}-dp_{n-j,k})\\&=\sum_{k=2}^m\sum_{i=1}^n(dp_{i,k}-dp_{i-1,k})\sum_{j=i}^n(dp_{n-j+1,k}-dp_{n-j,k})\end{aligned} \]

这样移一下 \(\sum\),然后可以将最后一个 \(j\)\(\sum\) 给后缀和预处理一下,就是平方了。

感觉这种基础的 DP 优化还算是我比较行的一项?其他大概就一无是处了吧

#include<bits/stdc++.h>
using namespace std;
const int mod=1000000007;
const int N=2000,M=N;
int n,m;
int dp[N+1][M+1];
int Sum[N+1][M+1],Sumk[N+1][M+1];
int sum[N+2];
int main(){
	cin>>n>>m;
	for(int i=2;i<=m;i++)dp[1][i]=1,Sum[1][i]=(Sum[1][i-1]+dp[1][i])%mod,Sumk[1][i]=(Sumk[1][i-1]-1ll*i*dp[1][i])%mod;
	for(int i=2;i<=n;i++)for(int j=2;j<=m;j++){
		dp[i][j]=(1ll*(j+1)*Sum[i-1][j]+Sumk[i-1][j]+1)%mod;
		Sum[i][j]=(Sum[i][j-1]+dp[i][j])%mod;
		Sumk[i][j]=(Sumk[i][j-1]-1ll*j*dp[i][j])%mod;
	}
	int ans=0;
	for(int k=2;k<=m;k++){
		for(int j=n;j;j--)sum[j]=(1ll*sum[j+1]+dp[n-j+1][k]-dp[n-j][k])%mod;
		for(int i=1;i<=n;i++)(ans+=1ll*(m-k+1)*(dp[i][k]-dp[i-1][k])%mod*sum[i]%mod)%=mod;
	}
	cout<<(ans+mod)%mod;
	return 0;
}
posted @ 2020-10-20 12:43  ycx060617  阅读(116)  评论(1编辑  收藏  举报