3175 小Y的疑惑
小 Y 有一个大小为n的背包,并且小Y有n种物品。(n<=100000)
对于第i种物品,共有i个可以使用,并且对于每一个i物品,体积均为i。
求小Y把该背包装满的方案数为多少,答案对于23333333取模。
定义两种不同的方案为:当且仅当至少存在一种物品的使用数量不同。
输入
输入一个整数n。
输出
输出一行,表示方案数。
数据范围
对于10%的数据,满足 n<=10
对于30%的数据,满足 n<=1000
对于50%的数据,满足 n<=10000
对于100%的数据,满足n<=100000
输入样例
输入样例1:
3
输出样例
输出样例1:
2
解析:
显然直接背包dp用前缀和做可以做到n2n2
考虑令
对于前kk小暴力背包
后面[k+1,n]的显然怎么选都不会超过个数的限制
令表示已经有个数,和为的方案数
考虑这样dp:
1、新加入一个大小为k+1的数
2、将之前ii个数每个都加1
显然这样是对的,且最多只有k个数
两部分复杂度都为
放代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
int const maxn=1e5+5,maxm=320,mod=23333333;
int n,f[maxn],g[maxm][maxn],s[maxn],t[maxn],ans;
int main()
{
scanf("%d",&n); int sq=sqrt(n);
f[0]=1;
for(int i=1;i<=sq;i++)
{
for(int j=0;j<=n;j++)s[j]=(f[j]+(j>=i?s[j-i]:0))%mod;
for(int j=0;j<=n;j++)
{
f[j]=s[j];
if(j>=(i+1)*i)f[j]=(f[j]-s[j-(i+1)*i]+mod)%mod;
}
}
g[0][0]=1;
ans=f[n];//
for(int i=1;i<=sq;i++)
for(int j=i*(sq+1);j<=n;j++)//i*
{
g[i][j]=(g[i-1][j-sq-1]+g[i][j-i])%mod;
ans=(ans+(ll)g[i][j]*f[n-j]%mod)%mod;
}
printf("%d\n",ans);
return 0;
}