你有一个大小为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 }