题目大意:
小 Y 有一个大小为
的背包,并且小Y有
种物品。
对于第
种物品,共有
个可以使用,并且对于每一个
物品,体积均为
。
求小Y把该背包装满的方案数为多少,答案对于
取模。
定义两种不同的方案为:当且仅当至少存在一种物品的使用数量不同。
思路:
体积小于
的物品个数很小,所以可以直接多重背包加前缀和优化一下。
体积大于
的物品都是永不完的,所以可以直接用完全背包。
裸的完全背包也不可以,观察到物品个数至多
个,所以设
表示在
个物品体积为
的方案数。转移的话这里有一个技巧,即分两种特殊的情况,第一种是
个物品的体积全部都大于
,这样的话
,可以看成前一种状态所有的物品的体积全部+1,最后还要算上包括了体积为
的情况,即
。
代码奇短无比。
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;++i)
#define DREP(i,a,b) for(int i=a;i>=b;--i)
typedef long long ll;
using namespace std;
void File(){
freopen("loj6089.in","r",stdin);
freopen("loj6089.out","w",stdout);
}
const int maxn=1e5+10;
const int maxm=320+10;
const ll mod=23333333;
int n,m;
ll sum[maxn],f[maxn],g[maxm][maxn],ans;
int main(){
//File();
scanf("%d",&n);
m=sqrt(n);
f[0]=1;
REP(i,1,m){
REP(j,0,i-1)sum[j]=f[j];
REP(j,i,n)sum[j]=(sum[j-i]+f[j])%mod;
DREP(j,n,i){
int num=min(i,j/i);
f[j]=(f[j]+sum[j-i]-((j-(num+1)*i<0) ? 0 : sum[j-(num+1)*i]))%mod;
}
}
REP(i,0,n)g[0][i]=f[i];
REP(i,1,m)REP(j,m+1,n)
g[i][j]=(g[i-1][j-m-1]+g[i][j-i])%mod;
REP(i,0,m)ans=(ans+g[i][n])%mod;
printf("%lld\n",ans);
return 0;
}