题意:
给出一个 (n imes m) 的矩阵,需对其进行黑白染色,使得以下条件成立:
- 存在区间 ([l,r])((1leq lleq rleq n)),使得第 (l,l+1,dots,r) 行恰有 (2) 个格子染成黑色,其余行所有格子均为白色。
- 设第 (i) 行染黑的两个格子所在的列为 (a_i,b_i(a_ilt b_i)),那么存在 (l leq t leq r),使得 (a_lgeq a_{l+1}geq a_{l+2}geqdotsgeq a_tleq a_{t+1}leq a_{t+2}leqdotsleq a_r),(b_lgeq b_{l+1}geq b_{l+2}geqdotsgeq b_tgeq b_{t+1}leq b_{t+2}leqdotsleq b_r)。
(n,m in [1,2000])
答案对 (10^9+7) 取模。
很显然可以分上部分和下部分考虑,这里考虑上半部分。
设 (dp_{i,j}) 表示填好了 (i) 行,第 (i) 行的“宽度”((b_i-a_i+1))为 (j)。
那么我们枚举上一行的宽度 (k),即 (dp_{i,j}=sumlimits_{k=2}^jdp_{i-1,k} imes(j-k+1))。
前缀和优化可以搞到 (n^2)。
然后我们考虑计算答案。
我们枚举上文中提到的 (t) 的位置,以及第 (t) 行的“宽度” (w),注意可能有多个 (t) 满足条件,这里我们枚举的是最下方的 (t),否则可能会重复计算。
这部分对答案的贡献为 (f(t,w)=(sumlimits_{i=1}^tdp_{i,w}) imes(1+sumlimits_{k=1}^{n-i}sumlimits_{l=2}^{w-1}dp_{k,l} imes(w-l+1)))
稍微解释一下这个式子。
前面的括号是填好上半部分的方案数,枚举行数求个和即可。
后面的括号的填好下半部分的方案数。第 (t+1) 行的宽度必然小于 (w),否则 (t+1) 也满足条件,我们枚举就不是“最下方的 (t)”了。
当然 (t+1) 行也可以不染色,贡献为 (1)。
预处理三个前缀和就可以 (mathcal O(1)) 求出 (f(t,w))。
最后 (ans=sumlimits_{t=1}^nsumlimits_{w=2}^mf(t,w) imes(m-w+1))
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define all(a) a.begin(),a.end()
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,0x3f,sizeof(a))
#define y1 y1010101010101
#define y0 y0101010101010
typedef pair<int,int> pii;
typedef long long ll;
const ll MOD=1e9+7;
ll n,m,dp[2005][2005],s1[2005][2005],s2[2005][2005],s[2005][2005],_s[2005][2005],__s[2005][2005];
int main(){
scanf("%d%d",&n,&m);
for(int i=2;i<=m;i++) dp[1][i]=1;
for(int j=2;j<=m;j++){
s1[1][j]=(s1[1][j-1]+dp[1][j])%MOD;
s2[1][j]=(s2[1][j-1]+dp[1][j]*j%MOD)%MOD;
}
for(int i=2;i<=n;i++){
for(int j=2;j<=m;j++){
dp[i][j]=(-s2[i-1][j]+s1[i-1][j]*(j+1)%MOD+MOD)%MOD;
// printf("%d %d %lld
",i,j,dp[i][j]);
}
for(int j=2;j<=m;j++){
s1[i][j]=(s1[i][j-1]+dp[i][j])%MOD;
s2[i][j]=(s2[i][j-1]+dp[i][j]*j%MOD)%MOD;
}
}
ll ans=0;
for(int i=1;i<=n;i++) for(int j=2;j<=m;j++) s[i][j]=(s[i-1][j]+dp[i][j])%MOD;
for(int i=1;i<=n;i++) for(int j=2;j<=m;j++) _s[i][j]=(_s[i][j-1]+s[i][j])%MOD;
for(int i=1;i<=n;i++) for(int j=2;j<=m;j++) __s[i][j]=(__s[i][j-1]+s[i][j]*j%MOD)%MOD;
for(int i=1;i<=n;i++) for(int j=2;j<=m;j++){
ans=(ans+s[i][j]*(_s[n-i][j-1]*(j+1)%MOD-__s[n-i][j-1]+MOD+1)%MOD*(m-j+1)%MOD)%MOD;
// printf("%d %d %lld
",i,j,s[i][j]*(_s[n-i][j-1]*(j+1)%MOD-__s[n-i][j-1]+MOD+1)%MOD*(m-j+1)%MOD);
}
printf("%lld
",ans);
return 0;
}
/*
dp[i][j]=sum dp[i-1][k]*(j-k+1)
sum s[x][k]*(j-k+1)
*/