[51nod1597]有限背包计数问题

分块,对于sqrt(n)以内的点用二进制优化多重背包+前缀和来做,处理出f[i][j]表示前i种权值为j的方案数
对于sqrt(n)以外的点有两个性质:1.与数量无关且数量不超过sqrt(n);2.权值相邻;3.那么一定可以用两种操作来构造出来权值序列:1.加入一个sqrt(n)+1;2.将现有数+1(都不超过n),再用g[i][j]表示选了i个(不是种)权值和为j,可以转移到g[i][i+j]和g[i+1][j+sqrt(n)+1],最后将两个卷起来(题目说恰好为n,所以不用fft)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 100005
 4 #define mod 23333333
 5 int K,n,ans,f[N],sum[N],g[320][N];
 6 int main(){
 7     scanf("%d",&n);
 8     K=(int)sqrt(n);
 9     f[0]=g[0][0]=1;
10     for(int i=1;i<=K;i++){
11         for(int j=0;j<i;j++)sum[j]=f[j];
12         for(int j=i;j<=n;j++)sum[j]=(sum[j-i]+f[j])%mod;
13         for(int j=0;j<i*i+i;j++)f[j]=sum[j];
14         for(int j=i*i+i;j<=n;j++)f[j]=(sum[j]-sum[j-i*i-i]+mod)%mod;
15     }
16     for(int i=0;i<=K;i++)
17         for(int j=0;j<=n;j++){
18             if ((i)&&(i+j<=n))g[i][i+j]=(g[i][i+j]+g[i][j])%mod;
19             if (j+K<n)g[i+1][j+K+1]=(g[i+1][j+K+1]+g[i][j])%mod;
20         }
21     for(int i=1;i<=K;i++)
22         for(int j=0;j<=n;j++)g[i][j]=(g[i][j]+g[i-1][j])%mod;
23     for(int i=0;i<=n;i++)ans=(ans+1LL*g[K][i]*f[n-i])%mod;
24     printf("%d",ans);
25 }
View Code

 

转载于:https://www.cnblogs.com/PYWBKTDA/p/11355851.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值