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;
    }
    
  • 相关阅读:
    单例类
    UITableView汇总
    JVM虚拟机——垃圾收集算法
    集合框架 HashMap 的扩容机制, ConcurrnetHashMap 的原理
    java判断两个单链表是否相交
    java中Comparator 和 Comparable的区别
    String getProperty(String key, String def)
    JAVA 单步调试快捷键
    Stanford Word Segmenter使用
    使用ifstream和getline读取文件内容[c++]
  • 原文地址:https://www.cnblogs.com/cjjsb/p/13360068.html
Copyright © 2011-2022 走看看