zoukankan      html  css  js  c++  java
  • LOJ #6089. 小 Y 的背包计数问题

    法老上课讲的题,感觉海星就写了下,比较常规的设阈值+DP

    首先我们考虑把物品分为两类,以(sqrt n)为阈值

    (ile sqrt n)时,显然现在物品总数很少,我们可以直接枚举每个物品然后做多重背包

    考虑使用多重背包的经典优化——完全背包差分,容易得出这部分的复杂度是(O(nsqrt n))

    然后当(i>sqrt n)时,显然此时每个物品最多拿(frac{n}{i})个,而(i>frac{n}{i}),因此物品个数可以看做无限制

    考虑用一个美妙的方法统计,设(f_{i,j})表示当前选了(i)个物品,体积和为(j)的方案数,转移操作有两种:

    • 新增一个物品,假定这个物品的体积为(sqrt n +1)
    • 将当前所有物品的体积都加(1)

    不难发现这样的每个方案都和一种选取方法唯一对应,因此是正确的,同时因为最多选(sqrt n)个物品,复杂度是(O(nsqrt n))

    综上,总体复杂度也是(O(nsqrt n))

    #include<cstdio>
    #include<cmath>
    #define RI register int
    #define CI const int&
    using namespace std;
    const int N=100005,M=330,mod=23333333;
    int n,m,f1[N],f2[M][N],g[N],ans;
    inline void inc(int& x,CI y)
    {
    	if ((x+=y)>=mod) x-=mod;
    }
    inline void dec(int& x,CI y)
    {
    	if ((x-=y)<0) x+=mod;
    }
    int main()
    {
    	RI i,j; for (scanf("%d",&n),m=sqrt(n),f1[0]=i=1;i<=m;++i)
    	{
    		for (j=i;j<=n;++j) inc(f1[j],f1[j-i]);
    		for (j=n;j>=i*(i+1);--j) dec(f1[j],f1[j-i*(i+1)]);
    	}
    	for (f2[0][0]=1,i=0;i<=m;++i) for (j=0;j<=n;++j)
    	{
    		inc(g[j],f2[i][j]);
    		if (j+m+1<=n) inc(f2[i+1][j+m+1],f2[i][j]);
    		if (j+i<=n) inc(f2[i][j+i],f2[i][j]);
    	}
    	for (i=0;i<=n;++i) inc(ans,1LL*f1[i]*g[n-i]%mod);
    	return printf("%d",ans),0;
    }
    
  • 相关阅读:
    Swap Nodes in Pairs
    Permutations(copy)
    Sort Colors
    Merge Two Sorted Lists
    Implement Queue using Stacks
    Best Time to Buy and Sell Stock
    Happy Number
    Gray Code
    springMVC初次搭建,产生错误
    JSP常用指令
  • 原文地址:https://www.cnblogs.com/cjjsb/p/13360068.html
Copyright © 2011-2022 走看看