Description
给出一个 n×m 的格子,每个格子要么黑色要么白色,要求其满足以下两个条件:
1.存在区间
[l,r](1≤r≤r≤n)
满足,第
l
行到第
2.存在
t(l≤t≤r)
满足,对于任意
i,j(l≤i≤j≤t)
,第
i
行两个黑色格子所在行形成的区间被第
问满足条件的染色方案数
Input
两个整数 n,m(1≤n,m≤2000)
Output
输出合法的染色方案数,结果模 109+7
Sample Input
4 4
Sample Output
485
Solution
相当于黑色格围成区域上半部分宽度不减,下半部分宽度不增,先求上半区域方案数,用
dp[i][j]
表示底边宽度为
j
且高至多为
dp[i][j]===1+∑k=2j(j−k+1)⋅dp[i−1][k]1+∑k=2j−1(j−1−k+1)⋅dp[i−1][j]+∑k=2jdp[i−1][k]dp[i][j−1]+∑k=2jdp[i−1][k]
转移过程中维护 ∑k=2jdp[i−1][k] ,则可以 O(1) 转移,进而该 dp 时间复杂度 O(nm)
现在考虑原问题,上半部分方案数已经算出来了,如果下半部分最宽处宽度和上半部分最宽处宽度相同则会记重,故下半部分最宽处宽度我们让其严格大于上半部分底边宽度,设下半部分最宽处宽度为
j
,则为使上半部分宽度严格小于
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=2005;
#define mod 1000000007
int n,m,dp[maxn][maxn];
void add(int &x,int y)
{
x=x+y>=mod?x+y-mod:x+y;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)dp[1][i]=1;
for(int i=2;i<=n;i++)
{
int sum=0;
dp[i][1]=1;
for(int j=2;j<=m;j++)
{
add(sum,dp[i-1][j]);
add(dp[i][j],dp[i][j-1]+sum);
}
}
int ans=0;
for(int i=1;i<=n;i++)
for(int j=2;j<=m;j++)
add(ans,(ll)(dp[i][j]-dp[i-1][j]+mod)*dp[n-i+1][j]%mod*(m-j+1)%mod);
printf("%d\n",ans);
return 0;
}