[CF1503E]2-coloring

壹、题目描述 ¶

传送门 to CF

贰、题解 ¶

个人认为官方题解说得很妙了,所以就去这里看吧......

只是推出来的式子有点不一样,我的是下面这样的:

\[2\sum_{p=1}^{m-1}\sum_{i=1}^n\sum_{j=i+1}^n{p-1+n-i\choose p-1}{p+i-1\choose i-1}{m+1-p-1+n-j\choose n-j}{m+1-p-2+j-1\choose j-1} \\ =2\sum_{p=1}^{m-1}\sum_{i=1}^n{p-1+n-i\choose p-1}{p+i-1\choose i-1}\sum_{j=i+1}^n{m-p+n-j\choose n-j}{m-p-2+j\choose j-1} \]

注意到 \(i\) 上面的不能和 \(j\) 贴在一起,所以不应该是从 \((0,n)\) 走到 \((i,j)\),而是从 \((0,n)\) 走到 \((i-1,j)\).

对于 \(j\) 下面也是同理,应该走到 \((i+1+1,j)\) 而不是 \((i+1,j)\).

单独看一看后面的东西:

\[\sum_{j=i+1}^n{m+1-p-1+n-j\choose n-j}{m+1-p-2+j-1\choose j-1} \\ =\sum_{j=i+1}^n{m-p+n-j\choose n-j}{m-p+j-2\choose j-1} \]

如果

\[f_{p,i}\overset{\Delta}{=}\sum_{j=1}^i{m+n-p-j\choose n-j}{m-p-2+j\choose j-1} \]

显然有递推式

\[f_{p,i}=f_{p,i-1}+{m+n-p-i\choose n-i}{m-p-2+i\choose i-1} \]

特别地,\(f_{p,0}=0\).

那么,答案计算就是

\[2\sum_{p=1}^{m-1}\sum_{i=1}^n{p-1+n-i\choose p-1}{p+i-1\choose i-1}(f_{p,n}-f_{p,i}) \]

考虑蓝色无路径时,我们把棋盘翻转一下,是不是又变成了填黄色的状态了?

但是如果我们考虑黄色、蓝色无路径时都这么做,会将“黄蓝都没有路径”的方案算两次,所以我们随便找“考虑黄色”或者“考虑蓝色”的计算过程,将 \(j\in[i+1,n]\) 变成 \(j\in[i+2,n]\) 即可,反映到前缀和上就是 \(f_{p,n}-f_{p,i}\) 变成了 \(f_{p,n}-f_{p,i+1}\).

时间复杂度 \(\mathcal O(nm)\).

叁、参考代码 ¶

#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;

#define Endl putchar('\n')
#define mp(a, b) make_pair(a, b)
#define rep(i, l, r) for(int i=(l), i##_end_=(r); i<=i##_end_; ++i)
#define fep(i, l, r) for(int i=(l), i##_end_=(r); i>=i##_end_; --i)
#define fi first
#define se second
typedef long long ll;
typedef pair<int, int> pii;
template<class T>inline T fab(T x){ return x<0? -x: x; }
template<class T>inline T readin(T x){
	x=0; int f=0; char c;
	while((c=getchar())<'0' || '9'<c) if(c=='-') f=1;
	for(x=(c^48); '0'<=(c=getchar()) && c<='9'; x=(x<<1)+(x<<3)+(c^48));
	return f? -x: x;
}

const int maxn=2021*2;
const int mod=998244353;

int C[maxn+5][maxn+5];

int f[maxn+5][maxn+5];

int n, m;

inline void input(){
	n=readin(1), m=readin(1);
	for(int i=0; i<=maxn; ++i){
		C[i][0]=C[i][i]=1;
		for(int j=1; j<i; ++j)
			C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
	}
}

inline void init(){
	rep(p, 1, m){ f[p][0]=0;
		rep(i, 1, n)
			f[p][i]=(f[p][i-1]+1ll*C[m+n-p-i][n-i]*C[m-p+i-2][i-1]%mod)%mod;
	}
}

signed main(){
	input();
	int ans=0;
	// rep(p, 1, m-1) rep(i, 1, n) rep(j, i+1, n)
	// 	ans=(ans+2ll*C[p-1+n-i][p-1]*C[p+i-1][i-1]%mod*C[m+1-p-1+n-j][n-j]%mod*C[m+1-p-2+j-1][j-1]%mod)%mod;
	// swap(n, m);
	// rep(p, 1, m-1) rep(i, 1, n) rep(j, i+2, n) // pay attention to +2
	// 	ans=(ans+2ll*C[p-1+n-i][p-1]*C[p+i-1][i-1]%mod*C[m+1-p-1+n-j][n-j]%mod*C[m+1-p-2+j-1][j-1]%mod)%mod;
	init();
	rep(p, 1, m-1) rep(i, 1, n-1) ans=(ans+2ll*C[p-1+n-i][p-1]*C[p+i-1][i-1]%mod*(f[p][n]+mod-f[p][i+1])%mod)%mod;
	swap(n, m); init();
	rep(p, 1, m-1) rep(i, 1, n) ans=(ans+2ll*C[p-1+n-i][p-1]*C[p+i-1][i-1]%mod*(f[p][n]+mod-f[p][i])%mod)%mod;
	printf("%d\n", ans);
	return 0;
}

肆、用到 の Trick

分析方案的特殊性质,通过这种特殊性质寻找方案。

比如此处的特殊性在于:

both of the following cannot hold:

  1. There exists a path of yellow cells from column \(1\) to column \(m\).
  2. There exists a path of blue cells from row \(1\) to row \(n\).

这两种只要其中一个不成立即可。

另外,我们发现这个颜色是越来越短的,这里还用到了一个巧妙地做法即从 \((1,0)\) 之类的边缘点开始走,就可以很好地表示最左边的动态的最长长度,而不用花费其他的东西,而且这个做法本身也很妙,用组合数表示了黄色的“越来越短”。

posted @ 2021-05-03 11:41  Arextre  阅读(60)  评论(0编辑  收藏  举报