zoukankan      html  css  js  c++  java
  • HDU7047 Link with Balls

    传送门


    这题比赛的时候没怎么认真想,俩队友似乎在这道题上花了很长时间,但遗憾的是也没搞出来,遂以为是一道难题。
    但正解竟出奇的简单。


    如果一对盒子,第一个可以选(k*i)个,第二个可以选(0sim i-1)个,那么任意的数都可以由这一对盒子选出来,而且方案唯一。这样就变成了(x_1+x_2+cdots+x_n=m)的非负整数解个数了,用插板法即可解决。

    但现在每一对盒子中的第二个可以选(0 sim i)个,那么当选了(i)的整数倍时,就会有两种选法,不好办了。

    于是题解给出了很漂亮的解决办法:我们让第(i)对盒子的第一个,和第(i-1)对盒子的第二个配对,即选(k*i)(0 sim i-1)配对,这样剩下的就只有(k * 1)(0 sim n)这两个盒子。于是我们只要枚举(0 sim n-1)这个盒子选多少个,再用插板法即可解决!

    (sumlimits_{i = 0}^{n}C_{m-i+n-1}^{n-1}).

    将上述式子进行化简,得到(sumlimits_{x = m-1}^{m+n-1}C_{x}^{n-1}=sumlimits_{x=0}^{m+n-1} C_{x}^{n-1}-sumlimits_{x=0}^{n-2}C_{x}^{n-1}).

    进而用( extrm{Hockey-Stick Identity})​​((C_{n}^{k+1}=sumlimits_{i=k}^{n-1} C_{i}^k)​)化简,最终得到(C_{n+m}^{n}-C_{m-1}^n).

    所以预处理(O(n)),单次询问(O(1)).


    更新

    最近加强了生成函数,在此也给出生成函数的做法吧:

    对于第(i)对盒子,第一个能拿(ki)个,那么对应的生成函数就是(f_{i}(x) = sumlimits_{n=0}^{infty} x^{ni}=frac1{1-x^{i}}),第二个能拿(0 sim i)个,对应的生成函数就是(g_{i}(x) = sumlimits_{n=0}^{i} x^n=frac{1-x^{n+1}}{1-x}).

    那么答案对应的多项式就是(prodlimits_{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}}.)

    于是我们将(frac{1-x^{n+1}}{(1-x)^{n+1}})用广义二项式定理展开,得到

    [egin{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;
    }
    
  • 相关阅读:
    HDU 3401 Trade
    POJ 1151 Atlantis
    HDU 3415 Max Sum of MaxKsubsequence
    HDU 4234 Moving Points
    HDU 4258 Covered Walkway
    HDU 4391 Paint The Wall
    HDU 1199 Color the Ball
    HDU 4374 One hundred layer
    HDU 3507 Print Article
    GCC特性之__init修饰解析 kasalyn的专栏 博客频道 CSDN.NET
  • 原文地址:https://www.cnblogs.com/mrclr/p/15127495.html
Copyright © 2011-2022 走看看