zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    Qt之json解析
    ListView
    JAVA的文件操作【转】
    可以随着SeekBar滑块滑动显示的Demo
    Android 之Buletooth
    VC++之运算符重载简单小结
    Android之Audio和Video
    Android之内容提供者ContentProvider的总结
    Android之Intent
    Android之Activity小结
  • 原文地址:https://www.cnblogs.com/zzqc/p/8528823.html
Copyright © 2011-2022 走看看