首页 > 其他分享 >归档 230418 // 补题

归档 230418 // 补题

时间:2023-04-18 16:55:43浏览次数:41  
标签:230418 return int 归档 补题 fac mkp inline mod

凳子充分地让我切身实地地体会到了平行四边形的不稳定性。做题的时候可以 360° 无死角地把下半身转来转去,有点意思。也有点容易摔(×

A. 两双手

http://222.180.160.110:1024/contest/3506/problem/1

不难发现可以通过解二元一次方程组得到用几个 A 操作和 B 操作才能让横纵坐标分别改变一些特定的值。可惜我没能想到一个经典的容斥 DP 思想:

定义起点为点 \(0\)。定义 \(C(x,y)\) 表示从 \(x\) 点走到 \(y\) 点的方案数(可经过特殊点)。对于特殊点 \(1\sim n\),顺序枚举,对于点 \(i\),定义 \(f_i\) 表示从 \(0\sim i\) 不经过任何除 \(i\) 以外的特殊点的方案数,则 \(f_i=C(0,i)-\sum\limits_{j=1}^{i-1}f_j\times C(j,i)\)。其中 \(\sum\limits_{j=1}^{i-1}f_j\times C(j,i)\) 就是从 \(0\) 到 \(i\),除 \(i\) 以外经过至少 1 个特殊点的方案数。用总方案数减去不合法方案数,则得到合法方案数。

一个细节。我们枚举时,可能会遇到只能从 \(i\) 到达 \(j\),而不能从 \(j\) 到达 \(i\) 的情况。若恰好 \(j\) 在 \(i\) 前面,那么从 \(i\) 到 \(j\) 的路径就会被统计漏。这个时候怎么办呢?对于任意点 \(i\),我们求得从 \(0\to i\) 所需的步数,并以此为关键字从小到大排序,那么我们就能保证,任意一条合法路径都会被我们统计到。

namespace XSC062 {
using namespace fastIO;
#define mkp std::make_pair
using pii = std::pair<int, int>;
const int lim = 1e6;
const int maxn = 505;
const int mod = 1e9 + 7;
const int maxm = 1e6 + 5;
struct _ { int x, y, w; };
std::set<pii> t;
_ s[maxn], s1[maxn];
int fac[maxm], f[maxn];
int ex, ey, n1, n, ax, ay, bx, by;
inline int gcd(int x, int y) {
	return y ? gcd(y, x % y) : x;
}
inline int lcm(int x, int y) {
	return x / gcd(x, y) * y;
}
pii Solve(int a, int b, int c,
				int d, int e, int f) {
	int N = 0, M = 0;
	if (!a) {
		if (c % b)
			return mkp(-1, -1);
		M = c / b, f -= M * e;
		if (f % d)
			return mkp(-1, -1);
		N = f / d;
	}
	else if (!b) {
		if (c % a)
			return mkp(-1, -1);
		N = c / a, f -= N * d;
		if (f % e)
			return mkp(-1, -1);
		M = f / e;
	}
	else if (!d) {
		if (f % e)
			return mkp(-1, -1);
		M = f / e, f -= M * b;
		if (c % a)
			return mkp(-1, -1);
		N = c / a;
	}
	else if (!e) {
		if (f % d)
			return mkp(-1, -1);
		N = f / d, c -= N * a;
		if (c % b)
			return mkp(-1, -1);
		M = c / b;
	}
	else {
		int g = lcm(b, e);
		a *= g / b, c *= g / b, b = g;
		d *= g / e, f *= g / e, e = g;
		if ((c - f) % (a - d))
			return mkp(-1, -1);
		N = (c - f) / (a - d), c -= N * a;
		if (c % b)
			return mkp(-1, -1);
		M = c / b;
	}
	return mkp(N, M);
}
inline int qkp(int x, int y) {
	int res = 1;
	while (y) {
		if (y & 1)
			(res *= x) %= mod;
		(x *= x) %= mod;
		y >>= 1;
	}
	return res;
}
inline int inv(int x) {
	return qkp(x, mod - 2);
}
inline int A(int n, int m) {
	return (fac[n] * inv(fac[n - m])) % mod;
}
inline int C(int n, int m) {
	return (A(n, m) * inv(A(m, m))) % mod;
}
inline void Init(void) {
	fac[0] = 1;
	for (int i = 1; i <= lim; ++i)
		fac[i] = (fac[i - 1] * i) % mod;
	return;
}
int main() {
	read(ex), read(ey), read(n1);
	read(ax), read(ay), read(bx), read(by);
	for (int i = 1; i <= n1; ++i) {
		read(s1[i].x), read(s1[i].y);
		pii t = Solve(ax, bx, s1[i].x,
						ay, by, s1[i].y);
		s1[i].w = t.first + t.second;
	}
	std::sort(s1 + 1, s1 + n1 + 1,
		[&](_ x, _ y) { return x.w < y.w; });
	Init(), f[0] = 1, ++n1;
	s1[n1].x = ex, s1[n1].y = ey;
	for (int i = 1; i <= n1; ++i) {
		pii t = Solve(ax, bx, s1[i].x,
						ay, by, s1[i].y);
		if (t.first < 0 || t.second < 0) {
			if (i == n1) {
				puts("0");
				return 0;
			}
			continue;
		}
		s[++n] = s1[i];
	}
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j < i; ++j) {
			pii t = Solve(ax, bx, s[i].x
				- s[j].x, ay, by, s[i].y
				- s[j].y);
			if (t.first < 0 || t.second < 0)
				continue;
			(f[i] += (f[j] * C(t.first +
					t.second, t.first)) %
					mod) %= mod;
		}
		pii t = Solve(ax, bx, s[i].x,
					ay, by, s[i].y);
		f[i] = (C(t.first + t.second,
				t.first) + mod - f[i]) % mod;
	}
	print(f[n]);
	return 0;
}
} // namespace XSC062

B. 绮丽的天空

http://222.180.160.110:1024/contest/3506/problem/2

标签:230418,return,int,归档,补题,fac,mkp,inline,mod
From: https://www.cnblogs.com/XSC062/p/17330225.html

相关文章