[loj6089]小 Y 的背包计数问题——背包计数+优化

题目大意:

小 Y 有一个大小为 n n 的背包,并且小Y有n种物品。
对于第 i i 种物品,共有i个可以使用,并且对于每一个 i i 物品,体积均为i
求小Y把该背包装满的方案数为多少,答案对于 23333333 23333333 取模。
定义两种不同的方案为:当且仅当至少存在一种物品的使用数量不同。

思路:

体积小于 n n 的物品个数很小,所以可以直接多重背包加前缀和优化一下。
体积大于 n n 的物品都是永不完的,所以可以直接用完全背包。
裸的完全背包也不可以,观察到物品个数至多 n n 个,所以设 g[i][j] g [ i ] [ j ] 表示在 i i 个物品体积为j的方案数。转移的话这里有一个技巧,即分两种特殊的情况,第一种是 i i 个物品的体积全部都大于n+1,这样的话 g[i][j]+=g[i][ji] g [ i ] [ j ] + = g [ i ] [ j − i ] ,可以看成前一种状态所有的物品的体积全部+1,最后还要算上包括了体积为 n+1 n + 1 的情况,即 g[i][j]+=g[i1][jn1] g [ i ] [ j ] + = g [ i − 1 ] [ j − n − 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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值