zoukankan      html  css  js  c++  java
  • 【51nod 1597】有限背包计数问题

    题目

    题目链接:http://www.51nod.com/Challenge/Problem.html#problemId=1597
    你有一个大小为 (n) 的背包,你有 (n) 种物品,第 (i) 种物品的大小为 (i),且有 (i) 个,求装满这个背包的方案数有多少。答案对 23333333 取模。
    两种方案不同当且仅当存在至少一个数 (i) 满足第 (i) 种物品使用的数量不同。
    (nleq 10^5)

    思路

    这题看上去就非常根号分治。考虑分别求出物品编号小于 (sqrt{n}) 和大于等于 (sqrt{n}) 时的背包,然后合并。
    首先来看小于 (sqrt{n})。此时每个物品是有不能取超过 (i) 个的限制的。由于物品数只有 (O(sqrt{n})),所以可以直接设 (f[i][j]) 表示前 (i) 个物品,使用了 (j) 的容量的方案数。
    然后有转移

    [f[i][j]=sum^{i}_{k=0}f[i-1][j-ki] ]

    就是枚举用多少个物品 (i)。这个玩意前缀和优化一下就好了。
    然后再看编号大于等于 (sqrt{n}) 的物品,我么发现这些物品一定是取不到上限的,所以其实等价于一个完全背包。
    有一个很经典的 trick:假设我们有一个序列 (a),我们可以通过如下操作构成这个序列:添加一个大小为 (1) 的物品,或者将所有物品大小加一。不难发现这个操作顺序与序列 (a) 是一一对应的。
    同理,设 (g[i][j]) 表示选择了 (i) 个编号超过 (sqrt{n}) 的物品,容量之和为 (j) 的方案数。那么考虑添加一个大小为 (sqrt{n}) 的物品,或者将所有物品大小加一,有

    [g[i][j]=g[i][j-i]+g[i-1][j-sqrt{n}] ]

    最后合并背包即可。注意需要滚动数组。
    时间复杂度 (O(nsqrt{n}))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=100010,M=320,MOD=23333333;
    int n,ans,f[2][N],g[2][N],h[N];
    
    int main()
    {
    	scanf("%d",&n);
    	f[0][0]=g[0][0]=1;
    	for (int i=1;i<M;i++)
    	{
    		int id=i&1;
    		memset(f[id],0,sizeof(f[id]));
    		for (int j=0;j<=n;j++)
    		{
    			h[j]=(f[id^1][j]+((j>=i) ? h[j-i] : 0))%MOD;
    			f[id][j]=(h[j]-((j>=i*(i+1)) ? h[j-i*(i+1)] : 0))%MOD;
    		}
    	}		
    	memset(h,0,sizeof(h));
    	for (int i=1;i<=M;i++)
    	{
    		int id=i&1;
    		memset(g[id],0,sizeof(g[id]));
    		for (int j=0;j<=n;j++)
    		{
    			if (j>=i) g[id][j]=(g[id][j]+g[id][j-i])%MOD;
    			if (j>=M) g[id][j]=(g[id][j]+g[id^1][j-M])%MOD;
    			h[j]=(h[j]+g[id][j])%MOD;
    		}
    	}
    	h[0]=1;
    	for (int i=0;i<=n;i++)
    		ans=(ans+1LL*f[1][i]*h[n-i])%MOD;
    	printf("%d",(ans%MOD+MOD)%MOD);
    	return 0;
    }
    
  • 相关阅读:
    Python使用SMTP模块、email模块发送邮件
    harbor搭建及使用
    ELK搭建-windows
    ELK技术栈之-Logstash详解
    【leetcode】1078. Occurrences After Bigram
    【leetcode】1073. Adding Two Negabinary Numbers
    【leetcode】1071. Greatest Common Divisor of Strings
    【leetcode】449. Serialize and Deserialize BST
    【leetcode】1039. Minimum Score Triangulation of Polygon
    【leetcode】486. Predict the Winner
  • 原文地址:https://www.cnblogs.com/stoorz/p/14700336.html
Copyright © 2011-2022 走看看