【LOJ6374】[SDWC2018 Day1]网格

【LOJ6374】[SDWC2018 Day1]网格

题面

loj

题解

先考虑一下没有限制而且可以同时不走的,那么显然行列是独立的。
( ext{f}(R,T,M))表示某一维走出步数(R),走(T)格,每步不超过(M),令生成函数( ext{F}(x)=1+x+x^2+cdots +x^M=frac {1-x^{M+1}}{1-x}),那么我们想求的就是([x^T] ext{F}(x)^R)
其中
( egin{aligned} ext{[}x^T ext{]} ext{F}(x)^R &=[x^T](frac {1-x^{M+1}}{1-x})^R\ &=[x^T](1-x^{M+1})^R(1+x+x^2+cdots)^R\ &=[x^T](1-x^{M+1})^Rsum_{i=0}^{infty}{i+R-1choose R-1}x^i\ &=sum_{i=0}^{lfloorfrac {T}{M+1} floor}(-1)^i{Rchoose i}{R-1+T-i(M+1)choose R-1} end{aligned} )

然后再考虑可以有((0,0))限制的:
可以发现( ext f(R,T_x,M_x) imes ext f(R,T_y,M_y))没有考虑((0,0)),那也就是至多走了(R)步的方案数,而非恰好
( ext g(R,T_x,T_y,M_x,M_y))表示恰好(R)步,然后里面参数自己看的答案,二项式反演得:
( ext g(R,T_x,T_y,M_x,M_y)=sum_{i=0}^R (-1)^{R-i}{Rchoose i} ext f(i,T_x,M_x) imes ext f(i,T_y,M_y))

现在再考虑有那(K)条限制的:
可以背包出( ext h(i,j))表示从(K)中选了(i)步走,走了(j imes G)格的方案数,那么放到总步数(R)中,方案数就有({R choose i} ext h(i,j))种。

最后就可以求出答案了:
考虑容斥,首先枚举至少踩了(i)条限制,再枚举限制走了(j imes G)步,那么答案为(不妨令(T_x<T_y))

[Ans=sum_{i=0}^R(-1)^i{R choose i}sum_{j=0}^{lfloorfrac {T_x}G floor} ext h(i,j) ext g(R-i,T_x-j imes G,T_y-j imes G,M_x,M_y) ]

计算的复杂度为(O(R^2lfloor frac TG floor)),可以通过。

代码

#include <bits/stdc++.h> 
using namespace std; 
int gi() { 
	int res = 0, w = 1; 
	char ch = getchar(); 
	while (ch != '-' && !isdigit(ch)) ch = getchar(); 
	if (ch == '-') w = -1, ch = getchar(); 
	while (isdigit(ch)) res = res * 10 + ch - '0', ch = getchar(); 
	return res * w; 
}
const int Mod = 1e9 + 7; 
int fpow(int x, int y) {
	int res = 1; 
	while (y) {
		if (y & 1) res = 1ll * res * x % Mod; 
		x = 1ll * x * x % Mod; 
		y >>= 1; 
	} 
	return res; 
} 
const int MAX_N = 1.2e6 + 5; 
int N = 1.2e6, Tx, Ty, Mx, My; 
int R, G, K, a[55]; 
int fac[MAX_N], ifc[MAX_N]; 
int C(int n, int m) { 
	if (n < m || n < 0 || m < 0) return 0; 
	else return 1ll * fac[n] * ifc[m] % Mod * ifc[n - m] % Mod; 
} 
int f(int R, int T, int M) { 
	int n = T / (M + 1), res = 0; 
	for (int i = 0; i <= n; i++) { 
		int now = 1ll * C(R - 1 + T - i * (M + 1), R - 1) * C(R, i) % Mod; 
		if (i & 1) res = (res - now + Mod) % Mod; 
		else res = (res + now) % Mod; 
	} 
	return res; 
} 
int g(int R, int Tx, int Ty, int Mx, int My) { 
	int res = 0; 
	for (int i = 0; i <= R; i++) { 
		int now = 1ll * C(R, i) * f(i, Tx, Mx) % Mod * f(i, Ty, My) % Mod; 
		if ((R - i) & 1) res = (res - now + Mod) % Mod; 
		else res = (res + now) % Mod; 
	} 
	return res; 
} 
int h[1005][1005]; 
int main () { 
#ifndef ONLINE_JUDGE 
    freopen("cpp.in", "r", stdin);
#endif 
	for (int i = fac[0] = 1; i <= N; i++) fac[i] = 1ll * fac[i - 1] * i % Mod; 
	ifc[N] = fpow(fac[N], Mod - 2); 
	for (int i = N - 1; ~i; i--) ifc[i] = 1ll * ifc[i + 1] * (i + 1) % Mod; 
	Tx = gi(), Ty = gi(), Mx = gi(), My = gi(); 
	R = gi(), G = gi(), K = gi(); 
	for (int i = 1; i <= K; i++) a[i] = gi() / G; 
	sort(&a[1], &a[K + 1]); K = unique(&a[1], &a[K + 1]) - a - 1; 
	h[0][0] = 1; 
	int mx = max(Tx, Ty) / G; 
	for (int i = 1; i <= min(mx, R); i++) 
		for (int j = 1; j <= K; j++) 
			for (int k = a[j]; k <= mx; k++) h[i][k] = (h[i][k] + h[i - 1][k - a[j]]) % Mod;
	int ans = 0; 
	for (int i = 0; i <= R; i++) { 
		int res = 0; 
		for (int j = 0; j <= mx; j++) 
			res = (res + 1ll * h[i][j] * g(R - i, Tx - j * G, Ty - j * G, Mx, My)) % Mod; 
		res = 1ll * res * C(R, i) % Mod; 
		if (i & 1) ans = (ans - res + Mod) % Mod; 
		else ans = (ans + res) % Mod; 
	} 
	printf("%d
", ans); 
    return 0; 
} 
原文地址:https://www.cnblogs.com/heyujun/p/13568339.html