[51nod1597] 有限揹包計數問題
阿新 • • 發佈:2019-02-20
題目大意
你有一個大小為n的揹包,你有n種物品,第i種物品的大小為i,且有i個,求裝滿這個揹包的方案數有多少
兩種方案不同當且僅當存在至少一個數i滿足第i種物品使用的數量不同
n≤100000,答案模23333333,時限2.333s
分析
這道題一看是一道多重揹包,但是範圍有點大啊。。。
可以嘗試利用一下題目的條件,對於
對於
但是直接上完全揹包又很慢。。。
但是可以注意到另一點:這些物品使用個數也不超過
轉移: [i][j]=g[i][j−i]+g[i−1][j−n√−1]
時間複雜度
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=100005,mo=23333333;
typedef long long LL;
int n,g[2][N],p,q,m,f[2][N],s,t,ans;
int main()
{
scanf("%d",&n);
for (m=n;m>n/m;m--);
p=0; q=1; f[0][0]=1;
for (int i=1;i<=m;i++,p^=1,q^=1)
{
memset(f[q],0,sizeof(f[q]));
for (int j=0;j<i;j++)
{
s=0;
for (int k=0;k*i+j<=n;k++)
{
s=(s+f[p][k*i+j])%mo;
f[q][k*i+j]=s;
if (k>=i) s=(s+mo-f[p][(k-i)*i+j])%mo;
}
}
}
t=p; ans+=f[t][n];
g[0][0]=1; p=0; q=1;
for (int i=1;i<=m;i++,p^=1,q^=1)
{
memset(g[q],0,sizeof(g[q]));
for (int j=m+1;j<=n;j++)
{
g[q][j]=g[p][j-m-1];
if (j>=i) g[q][j]=(g[q][j]+g[q][j-i])%mo;
}
for (int j=0;j<=n;j++) ans=(ans+(LL)f[t][j]*g[q][n-j])%mo;
}
printf("%d\n",ans);
return 0;
}