题目大意

任何正整数都能分解成2的幂,给定整数N,求N的此类划分方法的数量!

比如N = 7时,共有6种划分方法。

7=1+1+1+1+1+1+1
=1+1+1+1+1+2
=1+1+1+2+2
=1+2+2+2
=1+1+1+4
=1+2+4

最简单的方法

首先很容易想到用DP做。
设f[i][j]表示组成的数是i,方案中最大的数是2j2^j的方案数。
为了避免重复,f[i][j]转移时枚举下一个数必须大于等于2j2^j
那么可以得出:f[i][j]=∑jk=0f[i−2j][k]f[i][j]=\sum_{k=0}^j f[i-2^j][k]
注意到第一维是和k无关的,配合前缀和优化即可做到O(nlogn)O(nlogn)

相对巧妙的做法

状态太大了,可不可以减去一维?
设f[i]表示组成i的方案数。如果还是枚举下一个数来转移,那么时间复杂度没变。
那么考虑换一种转移方式。先给出方程:
f[i]=f[i−1]+f[i/2]∗[i是偶数]f[i]=f[i-1]+f[i/2]*[i是偶数]
f[i-1]转移到f[i]表示加入了一个1,f[i/2]则表示f[i/2]的分解方案中,全部数乘2。这样转移也保证了加进来数的顺序是从大到小的,故不会重复。

时间复杂度O(n)O(n)

跑得很快的做法

如果n很大怎么办?
那样就要挖掘一下分解方案的性质了。

  1. 对于一个数n,假设它二进制下有m个1,分别是第a1,a2…am位。对于n的任意一种分解方案,把所有2的幂升序排序,然后可以划分成m段,其中第i段的和是2ai2^{ai}
  2. 对于一个数2i2^i的一种划分方案,如果不是只有它本身一个数,一定可以把这些2的幂升序排序,然后分成两段,每一段的和都是2i−12^{i-1}

证明并不难。有了这些性质,就可以设新的状态了。

首先设g[i][j]表示做完了前i段(即n二进制下的前i个1位),最大的数是2j2^j,方案数是多少。
再设一个辅助数组f[i][j],表示组成2i2^i,最大的数是2j2^j的方案数。
接下来枚举第i-1段的最大数是多少,假设是2k2^k,那么g[i][j]=∑jk=0g[i−1][k]∗f[i−k][j−k]g[i][j]=\sum_{k=0}^j g[i-1][k]*f[i-k][j-k]
其中i-k,j-k的意义在于:要控制后面的数都大于等于2k2^k,每个数都要除掉2k2^k,那么就不会算重了。
f[i][j]的转移类似

时间复杂度O(log3n∗高精度)O(log^3n*高精度)

#include <cstdio>
#include <cstring>
#include <algorithm>using namespace std;const int N=99,M=170,mo=1e9;typedef long long LL;char c[N];int tot;struct num
{int w,a[M];
}f[N+5][N+5],ans,n,p,t,s[N+5],g[N+5][N+5];num operator + (const num &a,const num &b)
{t.w=max(a.w,b.w);//t.a[1]=0;memset(t.a,0,sizeof(t.a));for (int i=1;i<=t.w;i++){t.a[i]+=a.a[i]+b.a[i];if (t.a[i]>=mo){t.a[i+1]=1;t.a[i]-=mo;}//else t.a[i+1]=0;}if (t.a[t.w+1]>0) t.w++;//memset(t.a+t.w+1,0,sizeof(t.a+t.w+1));return t;
}num operator * (const num &a,const num &b)
{memset(t.a,0,sizeof(t.a));for (int i=1;i<=a.w;i++){for (int j=1;j<=b.w;j++){t.a[i+j]+=(t.a[i+j-1]+(LL)a.a[i]*b.a[j])/mo;t.a[i+j-1]=(t.a[i+j-1]+(LL)a.a[i]*b.a[j])%mo;}}for (t.w=a.w+b.w;t.w>1 && t.a[t.w]==0;t.w--);return t;
}int main()
{freopen("data.out","w",stdout);scanf("%s",c+1);int l=strlen(c+1);n.w=l/9+1;for (int i=1;i<=l;i++){int j=(l-i)/9;n.a[j+1]=n.a[j+1]*10+c[i]-48;}f[0][0].w=f[0][0].a[1]=1;for (int i=1;i<=N;i++){for (int j=0;j<i;j++){for (int k=0;k<=j;k++){f[i][j]=f[i][j]+f[i-1][k]*f[i-1-k][j-k];}}f[i][i].w=f[i][i].a[1]=1;}tot=0;for (int i=0;i<=N;i++){if (n.a[1]&1){tot++;if (tot==1){for (int j=0;j<=i;j++) g[1][j]=f[i][j];}else{for (int j=0;j<=i;j++){for (int k=0;k<=j;k++){g[tot][j]=g[tot][j]+g[tot-1][k]*f[i-k][j-k];}}}}int r=0;for (int j=n.w;j;j--){int t=n.a[j];n.a[j]=((LL)r*mo+t)/2;r=((LL)r*mo+t)%2;}}for (int i=0;i<=N;i++) ans=ans+g[tot][i];printf("%d",ans.a[ans.w]);for (int i=ans.w-1;i;i--){for (int j=1e8;j;j/=10){printf("%d",ans.a[i]/j);ans.a[i]%=j;}}printf("\n");return 0;
}

[51nod13831048]整数分解为2的幂相关推荐

  1. 51Nod-1383 整数分解为2的幂【数列】

    1383 整数分解为2的幂  任何正整数都能分解成2的幂,给定整数N,求N的此类划分方法的数量!由于方案数量较大,输出Mod 1000000007的结果. 比如N = 7时,共有6种划分方法. 7=1 ...

  2. 51nod 13831048 整数分解为2的幂 [递推]【数学】

    题目连接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1048 ---------------------------- ...

  3. 51Nod 13831048 整数分解为2的幂

    题目 任何正整数都能分解成2的幂,给定整数N,求N的此类划分方法的数量. V1:n≤106n≤106n≤10^6.要对答案模1e9+71e9+71e9+7. V2:n≤1030n≤1030n≤10^{ ...

  4. 51Nod 1048 1383 整数分解为2的幂

    任何正整数都能分解成2的幂,给定整数N,求N的此类划分方法的数量! 比如N = 7时,共有6种划分方法. 7=1+1+1+1+1+1+1 =1+1+1+1+1+2 =1+1+1+2+2 =1+2+2+ ...

  5. 【51NOD 1048】【51NOD 1383】整数分解为2的幂 V2

    Description 任何正整数都能分解成2的幂,给定整数N,求N的此类划分方法的数量! 比如N = 7时,共有6种划分方法. 7=1+1+1+1+1+1+1 =1+1+1+1+1+2 =1+1+1 ...

  6. [递推] 51Nod1383 整数分解为2的幂

    简单的递推,类似背包那种加 11 或翻倍的思路. 写这题其实只是水一篇 blogblog ,其实注意还是要做 51nod1048 加强版-- #include<cstdio> #inclu ...

  7. 数论 —— 整数分解

    [概述] 整数分解目前仍是世界级难题,是非常重要的研究方向,其有很多种算法,性能上各有差异,本文仅介绍试除法.Fermat 算法.Pollard Rho 算法. [试除法] 试除法也叫穷举法,是整数分 ...

  8. VJ 1033 整数分解(版本2)

    描述 整数分解(版本2) 一个正整数可以分解成若干个自然数之和.请你编一个程序,对于给出的一个正整数n(1<=n<=1500),求出满足要求的分解方案,并使这些自然数的乘积m达到最大. 例 ...

  9. JavaScript实现判断整数是否为2的幂isPowerOfTwo算法(附完整源码)

    JavaScript实现判断整数是否为2的幂isPowerOfTwo算法(附完整源码) isPowerOfTwo.js完整源代码 isPowerOfTwo.js完整源代码 /*** @param {n ...

最新文章

  1. jquery 只能输入汉字
  2. FFmpeg command line tool(Android中使用FFmpeg命令行)
  3. linux查看java运行日志,Linux下查看日志用到的经常使用命令
  4. zookeeper的设计猜想-Leader角色
  5. beta分布_浅谈脑电的beta频段振荡
  6. centos mysql 5.5.57_Centos MySQL 5.7安装、升级教程
  7. python模块调用模块_Python模块调用
  8. 基于Android的rgb七彩环颜色采集器
  9. Spring AOP配置文件
  10. c语言编译错误c267,为啥编译出现HAHA.C(31): error C267: 'adc0832': requires ANSI-style prototype.......
  11. matlab常用符号意思,matlab常用的符号
  12. promise对象---【阮一峰ES6】
  13. Adobe Dreamweaver的使用教程
  14. 富文本框TinyMCE4.8上传本地图片基本配置(前端篇)
  15. 【MySql】MySQL排序分页查询数据顺序错乱的原因和解决办法
  16. 2020秋季《大数据与物联网》期末答案参考
  17. XTU数据结构(C语言版)
  18. linux基础命令 - ps
  19. 2021-2027全球及中国燃料电池驱动系统行业研究及十四五规划分析报告
  20. 优秀是一种习惯:说一说你身边在世界名校读书的人

热门文章

  1. 前端播放视频有声音没有画面
  2. Spark RDD 特征及其依赖
  3. 路由器连接显示主服务器dns,路由器主dns服务器怎么设置 - 卡饭网
  4. dram sram drom srom ddram详细解释
  5. SQL 四大功能DDL/DML/DCL/TCL
  6. np.arry()的用法
  7. 基于Djiango的学生管理系统(含源代码)
  8. react-native实现微信分享和微信支付(安卓端)
  9. Java核心编程(22)
  10. fbx sdk android,FBX SDK环境配置