AGC001

E - BBQ Hard

  • 题意:有(n)个数对((A_i, B_i)),求$ sum_{i = 1}^{n} sum_{j = i+1}^{n} binom{A_i + A_j + B_i + B_j}{A_i + A_j} $ 并且(0 < A_i,B_i <= 2000).
  • 题解:有一个我跟本不知道的性质,即( binom{x + y}{x})就是指从点((0, 0))只能向上或者向右,走到点((x, y))的所有方案。既然这样,那么就可以从(A_i)(B_i)的大小来确定复杂度了,但是如果就设(dp[i][j])就是从原点到((i, j))的方案,我也不会知道咋算就是想,如果只是求一个( binom(n, m))那么结果就是让(dp[0][0] = 1),然后进行状态转移方程(dp[i][j] = dp[i][j] + dp[i-1][j] + dp[i][j-1]), (dp[n][m])就是答案,但是如果我们这样,让(dp[0+x][0+y] = 1),然后再进行状态转移方程,其实( binom(n, m))就应该是(dp[n + x][m +y]),这个也很重要,那么就了解了这个性质,我们让所有的起点都(++),然后就遍历所有终点就可以算了。因为最后注意$j > i (所以要先减去)j = i$的情况,再除以(2)即乘上(2)的逆元。
  • 代码:
#include <iostream>
#include <bits/stdc++.h>


using namespace std;

typedef long long ll;
const ll mod = 1e9 + 7;
const ll N = 200009;
ll fac[N];
ll q_mi(ll a, ll k, ll mod) {
	ll x = a;
	ll ret = 1;
	while (k) {
		if (k & 1)(ret *= x )%= mod;
		k >>= 1;
		(x *= x) %= mod;
	}return ret;
}
ll inv(ll x) {return (q_mi(x, mod - 2, mod) + mod) % mod;}

ll c(ll n,ll m) {return fac[n] * (inv(fac[m])) % mod * inv(fac[n-m]) % mod;}

ll a[N], b[N];

ll dp[5021][5021];
signed main() {
	ll n;
	cin >> n;
	for (ll i = 1; i <= n; i++) {
		cin >> a[i];
		cin >> b[i];
	}
	for (ll i = 1; i <= n; i++) {
		dp[2009-a[i]][2009-b[i]] ++;
	}
	for (ll i = 1; i <= 5000; i++) {
		for (ll j = 1; j <= 5000; j++) {
			(dp[i][j] += (dp[i-1][j] + dp[i][j-1]) % mod )%=mod;
		}
	}
	fac[0] = 1;
	for (ll i = 1; i <= N - 99; i++) (fac[i] = fac[i-1] * i % mod)%= mod;
	ll ans = 0;
	for (ll i = 1; i <= n; i++) {
		(ans = ((ans + dp[a[i] + 2009][b[i] + 2009] )%mod- c(2 * a[i] + 2 * b[i], 2 * a[i]) ) % mod +mod) %= mod;
	}
	(ans *= inv(2)) %= mod;
	cout << ans % mod << endl;
}
原文地址:https://www.cnblogs.com/Xiao-yan/p/14339410.html