• Codeforces 295D


    题意:
    给出一个 (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)
    */
    
  • 相关阅读:
    活动安排
    中国剩余定理
    欧拉回路
    单词游戏
    Ant Trip
    John's Trip
    太鼓达人
    相框
    原始生物
    Blockade
  • 原文地址:https://www.cnblogs.com/ET2006/p/Codeforces-295D.html
Copyright © 2020-2023  润新知