HDU7047 Link with Balls

傳送門


這題比賽的時候沒怎麼認真想,倆隊友彷佛在這道題上花了很長時間,但遺憾的是也沒搞出來,遂覺得是一道難題。
但正解竟出奇的簡單。


若是一對盒子,第一個能夠選\(k*i\)個,第二個能夠選\(0\sim i-1\)個,那麼任意的數均可以由這一對盒子選出來,並且方案惟一。這樣就變成了\(x_1+x_2+\cdots+x_n=m\)的非負整數解個數了,用插板法便可解決。php

但如今每一對盒子中的第二個能夠選\(0 \sim i\)個,那麼當選了\(i\)的整數倍時,就會有兩種選法,很差辦了。c++

因而題解給出了很漂亮的解決辦法:咱們讓第\(i\)對盒子的第一個,和第\(i-1\)對盒子的第二個配對,即選\(k*i\)和\(0 \sim i-1\)配對,這樣剩下的就只有\(k * 1\)和\(0 \sim n\)這兩個盒子。因而咱們只要枚舉\(0 \sim n-1\)這個盒子選多少個,再用插板法便可解決!git

即\(\sum\limits_{i = 0}^{n}C_{m-i+n-1}^{n-1}\).ide

將上述式子進行化簡,獲得\(\sum\limits_{x = m-1}^{m+n-1}C_{x}^{n-1}=\sum\limits_{x=0}^{m+n-1} C_{x}^{n-1}-\sum\limits_{x=0}^{n-2}C_{x}^{n-1}\).函數

進而用\(\textrm{Hockey-Stick Identity}\)​​(\(C_{n}^{k+1}=\sum\limits_{i=k}^{n-1} C_{i}^k\)​)化簡,最終獲得\(C_{n+m}^{n}-C_{m-1}^n\).ui

因此預處理\(O(n)\),單次詢問\(O(1)\).


更新spa

最近增強了生成函數,在此也給出生成函數的作法吧:code

對於第\(i\)對盒子,第一個能拿\(ki\)個,那麼對應的生成函數就是\(f_{i}(x) = \sum\limits_{n=0}^{\infty} x^{ni}=\frac1{1-x^{i}}\),第二個能拿\(0 \sim i\)個,對應的生成函數就是\(g_{i}(x) = \sum\limits_{n=0}^{i} x^n=\frac{1-x^{n+1}}{1-x}\).get

那麼答案對應的多項式就是\(\prod\limits_{i=0}^n f_i(x)*g_i(x)=\frac1{1-x}*(1+x) * \frac1{1-x^2} * \frac{1-x^3}{1-x} \cdots \frac1{1-x^{n-1}} * \frac{1-x^n}{1-x} * \frac1{1-x^n} * \frac{1-x^{n+1}}{1-x}=\frac{1-x^{n+1}}{(1-x)^{n+1}}.\)it

因而咱們將\(\frac{1-x^{n+1}}{(1-x)^{n+1}}\)用廣義二項式定理展開,獲得

 

\[\begin{align*} \frac{1-x^{n+1}}{(1-x)^{n+1}} &= \sum_{k=0}^{\infty} C_{n+k}^n x^k - x^{n+1} \sum_{k=0}^{\infty} C_{n+1}^n x^k\\ &= \sum_{k=0}^{\infty} C_{n+k}^n x^k - \sum_{j=n+1}^{\infty} C_{j-1}^n x^j\\ \end{align*}\]

 

那麼當\(m<n+1\)時,\(m\)次項的係數就是\(C_{n+m}^m\);
當\(m \geqslant n + 1\)時,\(m\)次項的係數是\(C_{n+m}^m - C_{m-1}^n\).

#include<bits/stdc++.h> 
using namespace std;
#define enter puts("") 
#define space putchar(' ')
#define In inline
typedef long long ll;
typedef double db;
const int maxn = 2e6 + 5;
const ll mod = 1e9 + 7;
In ll read()
{
	ll ans = 0;
	char ch = getchar(), las = ' ';
	while(!isdigit(ch)) las = ch, ch = getchar();
	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
	if(las == '-') ans = -ans;
	return ans;
}
In void write(ll x)
{
	if(x < 0) x = -x, putchar('-');
	if(x >= 10) write(x / 10);
	putchar(x % 10 + '0');
}

ll f[maxn], inv[maxn];
In ll C(int n, int m) 
{
	if(m > n) return 0;
	return f[n] * inv[m] % mod * inv[n - m] % mod;
}
In ll quickpow(ll a, ll b)
{
	ll ret = 1;
	for(; b; b >>= 1, a = a * a % mod)
		if(b & 1) ret = ret * a % mod;
	return ret;
}

int main()
{
	f[0] = inv[0] = 1;
	for(int i = 1; i < maxn; ++i) f[i] = f[i - 1] * i % mod;
	inv[maxn - 1] = quickpow(f[maxn - 1], mod - 2);
	for(int i = maxn - 2; i; --i) inv[i] = inv[i + 1] * (i + 1) % mod;
	int T = read();
	while(T--)
	{
		int n = read(), m = read();
		write((C(n + m, n) - C(m - 1, n) + mod) % mod), enter;
	}
	return 0;
}
相關文章
相關標籤/搜索