トムとマトリックス

説明文

\(\ sum_ {i = x1} ^ {x2} \ sum_ {j = y1} ^ {y2} C [i] [j] \%p \)

解決

組み合わせ番号の式は、\(C [i] [j] = C [i-1] [j-1] + C [i-1] [j] \)です。

この式はこのように理解できます。これはプレフィックスの合計です。jを列挙してからiを列挙すると、この配列は、このラウンドに関係のない数値を一度に追加することと同じです。

そして緊急に必要なのは、プレフィックス合計の最適化です。

次のように結論付けることができます。

\ [\ sum_ {i = x1} ^ {x2} C [i] [j] = C [x2 + 1] [j + 1] -C [x1] [j + 1](y1 <= j <= y2 )\]

説明:\(C [x1] [j + 1] \)\(\ sum_ {i = 1} ^ {x1-1} C [i] [j] \)です。前者も同じです。

コード

#include <cstdio>
typedef long long ll;

ll p, fac[100005];

int read() {
	int x = 0, f = 1; char s;
	while((s = getchar()) > '9' || s < '0') if(s == '-') f = -1;
	while(s <= '9' && s >= '0') {
		x = (x << 1) + (x << 3) + (s ^ 48);
		s = getchar();
	}
	return x * f;
}

ll qkpow(ll x, ll y) {
	ll r = 1;
	while(y) {
		if(y & 1) r = r * x % p;
		x = x * x % p; y >>= 1;
	}
	return r;
}

ll C(const int n, const int m) {
	if(n < m) return 0;
	return fac[n] * qkpow(fac[m] * fac[n - m] % p, p - 2) % p;
}

ll Lucas(const int n, const int m) {
	if(n < m) return 0;
	if(! m) return 1;
	return Lucas(n / p, m / p) * C(n % p, m % p) % p;
}

void init() {
	fac[0] = 1;
	for(int i = 1; i <= 100000; ++ i) fac[i] = fac[i - 1] * i % p;
}

int main() {
	int x1, x2, y1, y2; ll ans;
	while(~ scanf("%d %d %d %d %lld", &x1, &y1, &x2, &y2, &p)) {
		ans = 0; init();
		for(int i = y1; i <= y2; ++ i) ans = (ans + Lucas(x2 + 1, i + 1) - Lucas(x1, i + 1) + p) % p;
		printf("%lld\n", ans);
	}
	return 0;
}

おすすめ

転載: www.cnblogs.com/AWhiteWall/p/12752596.html