• [51nod1597]有限背包计数问题


      你有一个大小为n的背包,你有n种物品,第i种物品的大小为i,且有i个,求装满这个背包的方案数有多少
      两种方案不同当且仅当存在至少一个数i满足第i种物品使用的数量不同

     Input
      第一行一个正整数n
      1<=n<=10^5
     Output
      一个非负整数表示答案,你需要将答案对23333333取模

     
    首先我们可以发现,令S=sqrt(n),那么对于大小大于S的物品,其实是用不完的,我们可以把他们的数量视为无限个
    对于大小小于S的物品,我们可以令f[i][j]表示考虑了前i个物品,总大小为j的方案数,那么有:
    f[i][j]=sum{f[i-1][j-k*i]},0<=k<=i
    我们在DP的时候,假设当前要计算f[i][j],可以设tmp[v]为当前满足t mod i=v的f[i-1][t]的和
    然后就可以通过维护tmp数组,轻松计算出f[i][j]了
    这一步的时间复杂度是O(nsqrt(n))
     
    接下来考虑大小大于S的物品
    我们考虑一个给物品“动态添加大小”的DP:
    令g[i][j]表示,当前有i个物品,大小总和为j
    我们可以做的转移是:
    (1):将所有物品的大小加一 :g[i][j]->g[i][j+i]
    (2):新建一个大小为S+1的物品g[i][j]->g[i+1][j+S+1]
    可以发现,物品总数最多为n/S个,所有g的第一维的规模是n/S的,所以这一个DP也是O(n*sqrt(n))的
    于是总复杂度就是O(n*sqrt(n))
    这道题还有更加优美的算法,可以用多项式黑科技进行推导,可以得到复杂度O(nlogn)的做法,由于出题人能力有限所以这里就不阐述了
     
     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<queue>
     6 #include<cmath>
     7 #define ll long long
     8 #define ui unsigned int
     9 #define ull unsigned long long
    10 const int maxn=100233,modd=23333333;
    11 int f[2][maxn],g[2][maxn],sm[maxn],tmp[maxn];
    12 int i,j,k,n,m,n1;
    13 
    14 int ra;char rx;
    15 inline int read(){
    16     rx=getchar(),ra=0;
    17     while(rx<'0'||rx>'9')rx=getchar();
    18     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
    19 }
    20 
    21 #define MOD(x) x-=x>=modd?modd:0
    22 #define UPD(x) x+=x<0?modd:0
    23 int main(){
    24     n=read(),n1=sqrt(n);register int i,j,k;
    25     
    26     bool now=1,pre=0;f[0][0]=1;int mod;
    27     for(i=1;i<=n1;i++,std::swap(now,pre)){
    28         memset(tmp,0,i<<2),mod=-1;
    29         for(j=0,k=-i*i;j<=n;j++,k++){
    30             if(++mod>=i)mod=0;
    31             tmp[mod]+=f[pre][j],MOD(tmp[mod]),
    32             f[now][j]=tmp[mod];
    33             if(k>=0)tmp[mod]-=f[pre][k],UPD(tmp[mod]);
    34         }
    35     }//printf("n1:%d
    ",n1);
    36     //for(i=1;i<=n;i++)printf("  %d",f[pre][i]);puts("");
    37     int n2=n/n1;
    38     bool now1=1,pre1=0;g[0][0]=1;
    39     for(i=1;i<=n2;i++,std::swap(now1,pre1)){
    40         memset(g[now1],0,(n1+1)<<2);
    41         for(j=n1+1,k=0;j<=n;j++,k++)g[now1][j]=g[pre1][k];
    42         for(j=i;j<=n;j++)g[now1][j]+=g[now1][j-i],MOD(g[now1][j]);
    43         for(j=1;j<=n;j++)sm[j]+=g[now1][j],MOD(sm[j]);
    44     }
    45     int ans=f[pre][n]+sm[n];MOD(ans);
    46     for(i=1;i<n;i++)ans=(ans+1ll*f[pre][i]*sm[n-i])%modd;
    47     printf("%d
    ",ans);
    48 }
    View Code
  • 相关阅读:
    03server
    Storm介绍(一)
    storm总结
    Spring源码分析(七)扩展接口BeanPostProcessors源码分析
    技术大牛养成指南
    02装配bean
    02Activity
    maven构建项目
    IDEA使用
    从GIt上导出Maven项目
  • 原文地址:https://www.cnblogs.com/czllgzmzl/p/5946998.html
Copyright © 2020-2023  润新知