zoukankan      html  css  js  c++  java
  • HDU6042 Journey with Knapsack

    传送门


    题面:一个体积为(2*n)的背包,有(n(nleqslant 5*10^4))种食物,第(i)种食物的体积是(i),数量是(a_i(0 leqslant a_1<a_2< cdots <a_n leqslant 2*n)),还有(m)种装备,第(i)种装备的体积是(b_i(1leqslant b_i leqslant 2*n)),求装一些食物和一件装备使得背包装满的方案数。
    (感谢博主HopeForBetter的翻译)


    这题算是比较明显的组合问题了,如果我们能算出一定体积装食物的方案数,那枚举装备即可。

    食物的方案数的生成函数很好构造:(f(x)=prodlimits_{i=1}^n frac{1-x^{(a_i+1)i}}{1-x^i}).

    关键是怎么求这个式子的第(i)项的系数。

    首先要明确的是,我么只要小于等于(x^{2n})项的系数,即模(x^{2n+1})的条件下这些多项式的乘积,所以以下所有运算都是在模(x^{2n+1})条件下的。

    我们将该式子分成两部分:(f(x) = prodlimits_{i=1}^n (1-x^{(a_i+1)i}) * prodlimits_{i=1}^n frac1{1-x^i}).


    1.求(prodlimits_{i=1}^n (1-x^{(a_i+1)i}))
    注意到有(0 leqslant a_1 < a_2 < cdots < a_n leqslant 2n),因此(a_i+1 geqslant i),所以((a_i+1)i geqslant i^2),那么最多只有(sqrt{n})项有用,因此可以先求后面部分的系数,然后暴力和这(O(sqrt{n}))(1-x^{(a_i+1)i})相乘。


    2.求(prodlimits_{i=1}^n frac1{1-x^i})
    这个式子是不是很熟悉?确实,他跟整数划分的生成函数非常像,只不过是用(1 sim n)的数来组成小于等于(2n)的数的方案数,和整数划分又有些不同。

    那么我们干脆补成整数划分的正规形式:(prodlimits_{i=1}^n frac1{1-x^i} = prodlimits_{i=1}^{2n} frac1{1-x^i} * prodlimits_{i=n+1}^{2n} (1-x^i)).

    (p(i))表示将(i)划分成若干个整数相加的方案数,那么上式化简为(sumlimits_{i=1}^{2n}p(i)x^i prodlimits_{i=n+1}^{2n} (1-x^i)=sumlimits_{i=1}^{2n}p(i)x^i (1-sumlimits_{i=n+1}^{2n}x^i))

    最后那一个连乘化简我想了半天,因为(i in [n+1,2n]),所以任意两个相乘必然大于(2n),那被(x^{2n+1})取模后就没了,因此只能有单独的一项。

    (p(i))有公式(p(n)=sum_{k geqslant 1} (-1)^{k+1}[p(n-frac{k(3k+1)}{2})+p(n-frac{k(3k-1)}{2})]),可以(O(nsqrt{n}))预处理。

    而上述的式子也可以(O(n))相乘:乘以(sumlimits_{i=n+1}^{2n}x^i)相当于分别把([n+1,2n])次项加上了([0,n-1])项的系数,([n+2,2n])项加上了([0,n-2])的系数,([n+3,2n])加上了([0,n-3])的系数……那也就是说,(x^{n+1})项要加上(x^{0})项的系数,(x^{n+2})项要加上(x^0,x^1)的系数,(x^{n+3})要加上(x^0,x^1,x^2)的系数……其本质就是一个前缀和。


    综上,这道题还是挺有难度的,包括观察出整数划分,以及(O(n))(sum x^i)这种多项式相乘,我都要再消化消化。

    #include<bits/stdc++.h> 
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 5e4 + 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');
    }
    
    In ll ADD(const ll& a, const ll& b) {return a + b < mod ? a + b : a + b - mod;}
    
    int n, m, a[maxn], b[maxn << 1];
    
    ll p[maxn << 1], f[maxn << 1];
    In ll solve()
    {
    	int N = n << 1; p[0] = 1;
    	for(int i = 1; i <= N; ++i)					//求p(n) 
    	{
    		p[i] = 0;
    		for(int k = 1; k <= n; ++k)
    		{
    			int t = k * (3 * k - 1) >> 1;
    			if(t > i) break;
    			p[i] = ADD(p[i], (k & 1) ? p[i - t] : mod - p[i - t]);
    			t = k * (3 * k + 1) >> 1;
    			if(t > i) continue;
    			p[i] = ADD(p[i], (k & 1) ? p[i - t] : mod - p[i - t]);
    		}
    	}
    	fill(f, f + N + 1, 0);
    	for(int i = 0; i < n; ++i) f[i + n + 1] = mod - p[i];		//乘以-∑x^i 
    	for(int i = 1; i <= N; ++i) f[i] = ADD(f[i], f[i - 1]);
    	for(int i = 0; i <= N; ++i) f[i] = ADD(f[i], p[i]);
    	for(int i = 1; i <= n; ++i)				        //乘以第一部分 
    	{	
    		int t = (a[i] + 1) * i;
    		if(t > N) break;
    		for(int i = N; i >= t; --i) f[i] = ADD(f[i], mod - f[i - t]);
    	}
    	ll ans = 0;
    	for(int i = 1; i <= m; ++i) ans = ADD(ans, f[N - b[i]]);
    	return ans;
    }
    
    int main()
    {
    	int T = 0;
    	while(scanf("%d%d", &n, &m) != EOF)
    	{
    		for(int i = 1; i <= n; ++i) a[i] = read();
    		for(int i = 1; i <= m; ++i) b[i] = read();
    		printf("Case #%d: %lld
    ", ++T, solve());
    	}
    	return 0;
    }
    
  • 相关阅读:
    【和我一起学python吧】Python安装、配置图文详解
    【和我一起学python吧】初学Python,版本如何选择?
    CSS使用简介
    css样式表中的样式覆盖顺序
    转载-ActiveMQ通过JAAS实现的安全机制
    消息队列开发记录笔记-ActiveMQ
    转载-使用消息队列的 10 个理由
    在linux或mac终端下将命令结果输出到文件保存
    ideviceinstaller命令(类似android的adb)
    mac安装mysql及导库
  • 原文地址:https://www.cnblogs.com/mrclr/p/15150150.html
Copyright © 2011-2022 走看看