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;
    }
    
  • 相关阅读:
    IE6实现PNG图片透明
    xp精简版 安装IIS
    CSS 多浏览器兼容又一方案
    mysql忘记root帐号和密码,修改root用户名和密码解决方案
    jQuery函数学习
    建立标准化的声明DOCTYPE和head
    关于Microsoft.XMLDOM 与Microsoft.XMLHTTP
    伪静态技术(较完整篇)
    关于document.cookie的使用
    鼠标滚动缩放图片效果
  • 原文地址:https://www.cnblogs.com/mrclr/p/15127495.html
Copyright © 2011-2022 走看看