51nod-1259-分块+dp

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1259

 

  1259 整数划分 V2

基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题
收藏
关注
将N分为若干个整数的和,有多少种不同的划分方式,例如:n = 4,{4}  {1,3}  {2,2}  {1,1,2} {1,1,1,1},共5种。由于数据较大,输出Mod 10^9 + 7的结果即可。
Input
输入1个数N(1 <= N <= 50000)。
Output
输出划分的数量Mod 10^9 + 7。
Input示例
4
Output示例
5

与1201相似但是允许出现重复的数,如果还按照1201的写法,复杂度就是平方级了,看了讨论的解法感觉很巧妙。
利用分块将数据分成了[1,sqrt(n)],[sqrt(n)+1,n]两部分,分别用f[i][j]和g[i][j]表示用区间内的数j个组合成和为i的数的方案个数,计算f时无限背包,计算g时使用1201的
方程计算(注意这里的区间最小的值是sqrt(n+1))。最后用乘法原理计算答案ans=SUM{f[n][i]*h[n-i]},其中0<=i<=n,h[i]表示g[i][..]的总和。注意乘法时候会爆int使用longlong就好了。
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int mod=1e9+7;
 4 #define LL long long
 5 int f[50005],g[50005][330];
 6 int main()
 7 {
 8     int n,i,j,k;
 9     cin>>n;
10     f[0]=1;
11     int m=sqrt(n*1.0);
12     for(i=1;i<=m;++i)
13         for(j=i;j<=n;++j)
14      f[j]=(f[j]+f[j-i])%mod;
15      
16      g[0][0]=1;
17      g[m+1][1]=1;
18     for(i=m+1;i<=n;++i)
19     {
20         int k=i/(m+1);
21         for(j=1;j<=k;++j)
22         {
23             if(i+j<=n){
24             g[i+j][j]=(g[i+j][j]+g[i][j])%mod;
25             }
26             if(i+m+1<=n){
27             g[i+m+1][j+1]=(g[i+m+1][j+1]+g[i][j])%mod;
28             }
29             g[i][0]=(g[i][0]+g[i][j])%mod;
30         }
31     }
32     LL ans=0;
33     for(i=0;i<=n;++i)
34         ans=(ans+(LL)f[i]*g[n-i][0]%mod)%mod;
35     cout<<ans<<endl;
36     return 0;
37 }

 

转载于:https://www.cnblogs.com/zzqc/p/8528823.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值