Description
任何正整数都能分解成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
(1 <= N <= 10^30)
Solution
O(N)的做法十分显然。
f[i]=f[i−1]+f[i/2]
,当i为偶数
f[i]=f[i−1]
当i为奇数。
既然N这么大了,考虑log 做法
假定
N=2p
似乎它与
2p−1
有一定关系。
设
f[i][l][r]
表示做到
2i
,当前分解最大的数是
2r
,最小的是
2l
这样很好的避免了重复问题。
显然
f[i][l][r]=∑k=lrf[i−1][l][k]∗f[i−1][k][r]
log4N
似乎有点大。
事实上,
f[i][l][r]=f[i−1][l−1][r−1]
(即分解的所有数同时除以2)
那么只需要保存
f[i][0][r]
就足够。
DP就变为2维的了。
复杂度
log3N
N不是 2l 怎么办。
完全可以将N二进制分解,在有1的位置做DP,方法同上面相同,因为两个二进制位间相互独立,互不影响。相当于将前面所有二进制位合并后,与当前位合并,一直合并下去。
复杂度同样
log3N
高精度注意常数优化。
Code
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define N 105
#define cl(a) memset(a,0,sizeof(a));
#define lq 1000000000
using namespace std;
typedef long long LL;
int m,p[N];
LL cf[11];
struct node
{
int a[180];
}f[N][N],g[N][N],n;
node operator *(node x,node y)
{
node z;
cl(z.a);
z.a[0]=x.a[0]+y.a[0]-1;
if((!x.a[1]&&x.a[0]<2)||(!y.a[1]&&y.a[0]<2))
{
z.a[0]=1,z.a[1]=0;
return z;
}
fo(i,1,x.a[0])
{
fo(j,1,y.a[0])
{
LL v=(LL)x.a[i]*(LL)y.a[j]+(LL)z.a[i+j-1];
z.a[i+j]+=(int)(v/lq);
z.a[i+j-1]=(int)(v%lq);
}
}
if(z.a[z.a[0]+1]) z.a[0]++;
return z;
}
node operator +(node x,node y)
{
node z;
cl(z.a);
z.a[0]=max(x.a[0],y.a[0]);
fo(i,1,z.a[0])
{
z.a[i+1]+=(z.a[i]+=x.a[i]+y.a[i])/lq;
z.a[i]%=lq;
}
z.a[0]+=(z.a[z.a[0]+1]);
return z;
}
node operator /(node x,LL y)
{
node z;
memset(z.a,0,sizeof(z.a));
z.a[0]=x.a[0];
fod(i,z.a[0],1)
{
if(i!=1) z.a[i-1]+=(z.a[i]+x.a[i])%y*lq;
z.a[i]=(z.a[i]+x.a[i])/y;
}
z.a[0]-=(!z.a[z.a[0]]);
return z;
}
int get()
{
node n1=n;
int i=0;
while(n1.a[0])
{
if(n1.a[1]%2) p[++p[0]]=i;
n1=n1/2,i++;
}
return i;
}
int main()
{
char st[2000];
scanf("%s",st+1);
cf[0]=1;
fo(i,1,10) cf[i]=cf[i-1]*10;
int l1=strlen(st+1);
fo(i,1,l1) n.a[(i-1)/9+1]+=(st[l1-i+1]-'0')*cf[i-(i-1)/9*9-1];
n.a[0]=(l1-1)/9+1;
int l=get();
f[0][0].a[0]=f[0][0].a[1]=1;
int v=0;
fo(i,1,l)
{
f[i][i].a[0]=f[i][i].a[1]=1;
fo(j,0,i-1)
{
f[i][j].a[0]=1;
f[i][j].a[1]=0;
fo(k,0,j) f[i][j]=f[i][j]+f[i-1][k]*f[i-1-k][j-k];
}
}
fo(i,0,p[1]) g[1][i]=f[p[1]][i];
fo(i,2,p[0])
{
fo(j,0,p[i])
{
fo(k,0,j) g[i][j]=g[i][j]+g[i-1][k]*f[p[i]-k][j-k];
}
}
node ans;
cl(ans.a);
fo(i,0,p[p[0]]) ans=ans+g[p[0]][i];
fod(i,ans.a[0],1)
{
if(i!=ans.a[0]) fod(j,8,1) if(ans.a[i]<cf[j]) printf("0");
printf("%d",ans.a[i]);
}
}