CF295D Solution

题解

设dp状态\(dp[i][j]\)表示前\(i\)行黑色单元格间列数(含黑色)单调不降且第\(i\)行列数为\(j\)的方案数,也就是\(t\)行及以上部分的方案数。因为洞的左右位置不影响它的形态,所以只需记录列数而非左右端点。\(dp[i][j]=\sum\limits_{k=2}^mdp[i-1][k]\times (j-k+1)\),可以发现等式右侧是\(dp[i-1]\)前缀和的前缀和,可以\(O(1)\)求出。\(t\)行以下的部分与上部相同,也可使用\(dp\)数组。枚举\(t\),为避免重复计算,令行\([i,t]\)中没有黑色单元格间列数与第\(t\)行相等的行,答案增加\((dp[t][j]-dp[t-1][j])\times dp[n-t+1][j]\)(上部方案数乘下部方案数)。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=2010,mod=1e9+7;
int dp[N][N];
inline int read()
{
    int s=0,w=1; char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-') w=-1; ch=getchar();}
    while(ch>='0' && ch<='9') s=s*10+ch-'0',ch=getchar();
    return s*w;
}
int main()
{
    int n=read(),m=read(),sum1,sum2,ans=0;
    for(int i=2;i<=m;i++) dp[1][i]=1;
    for(int i=2;i<=n;i++)
    {
        sum1=sum2=0;
        for(int j=2;j<=m;j++)
        {
            sum1=(sum1+dp[i-1][j])%mod,sum2=(sum2+sum1)%mod;
            dp[i][j]=(sum2+1)%mod;
        }
    }
    for(int i=2;i<=m;i++)
    {
        for(int j=1;j<=n;j++)
            ans=(ans+1ll*(dp[j][i]-dp[j-1][i]+mod)*dp[n-j+1][i]%mod*(m-i+1)%mod)%mod;
    }
    printf("%d",ans);
    return 0;
}
posted @ 2021-10-11 18:06  violet_holmes  阅读(41)  评论(0编辑  收藏  举报