题解:CF295D Greg and Caves / [SNOW] - 73
fish_love_cat · · 题解
*2400 调一万年我有救了。
这个玩意是对称的,考虑确定
考虑到这个方案数依赖于上一行的长度,并且注意到我们知道向上扩展
假了,假一万年。
终于你发现如果这个洞中间一段长度完全相同的时候有多个
如何去重?我们钦定符合条件的
那么我们这个时候的方案就是原先 dp 的转移数组上长度维度减一得到的位置上的方案数……吗?
假了,再假一万年。
注意到这个时候的意义等价于废掉一个固定的点不可使用,但这个显然会少算。
事实上是存在这个边界上的点产生贡献的方案的。
那么我们只需要再写一遍 dp 转移出必然使用这个废点的方案数加回去就做完了。
然后你发现这样做会是
然后你又注意到这两轮 dp 都可以上前缀和优化,于是时间复杂度
转移方程顺着意义就可以推出来,难点不在这里可以直接看代码。
#include<bits/stdc++.h>
#define mod 1000000007
#define int long long
using namespace std;
int dp[2005][2005];
int sum[2005][2005];
int dp2[2005][2005];
void solve(){
int n,m;
cin>>n>>m;
int ans=0;
for(int i=1;i<=n;i++)
for(int j=2;j<=m;j++)
ans=(ans+(m-j+1)*dp[i-1][j]%mod*((dp[n-i][j-1]+dp2[n-i][j-1])%mod)%mod)%mod;
cout<<ans;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int n=2000;
for(int i=0;i<=n;i++)
dp[0][i]=1;
for(int j=2;j<=n;j++)sum[0][j]=dp[0][j];
for(int j=3;j<=n;j++)sum[0][j]=(sum[0][j-1]+sum[0][j])%mod;
for(int j=3;j<=n;j++)sum[0][j]=(sum[0][j-1]+sum[0][j])%mod;
for(int i=1;i<=n;i++){
for(int j=2;j<=n;j++)
dp[i][j]=(dp[i][j]+sum[i-1][j])%mod;
for(int j=0;j<=n;j++)dp[i][j]++;
for(int j=2;j<=n;j++)sum[i][j]=dp[i][j];
for(int j=3;j<=n;j++)sum[i][j]=(sum[i][j-1]+sum[i][j])%mod;
for(int j=3;j<=n;j++)sum[i][j]=(sum[i][j-1]+sum[i][j])%mod;
}
for(int i=1;i<=n;i++){
for(int j=2;j<=n;j++)
dp2[i][j]=(dp2[i][j-1]+dp[i-1][j]%mod)%mod;
}
int t=1;
// cin>>t;
while(t--)solve();
return 0;
}
// 面包店的老板也说:
//「啊啊,魔女小姐。你也看到了吧?那孩子每次都拿那种东西来买面包。我知道她很可怜——不过我们也是做生意的,不知道该怎么办啊。」
我觉得有紫啊,每假一次都得手玩好久的 hack 然后再改,改对另说改错就再瞪一万年,而且边界的分讨需要仔细,上前缀和优化的时候不小心写挂点东西又要重构,一整个数哭出来了。到底简单在哪 T_T
万人血书请求升紫(1 / 10000)