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
Solution
设
gi,j,k
表示一个序列组成
2i
这个数,这个序列中最大的数为
2j
,最小的为
2k
的方案数;
设
fi,j
表示已经做完了输入的数的后i位二进制,序列中最大的数为
2j
的方案数;
gi,j,k=∑l=kjgi−1,j,l∗(∑t=klgi−1,t,k)
fi,j=∑k=1jgi,j,k∗(∑l=1kfi−1,l)
有两个很显然可以用前缀和,
复杂度: O(n4)
优化:
发现有性质
gi,j,k=gi−1,j−1,k−1=gi−2,j−2,k−2=......
所以只要记录 g′i,j 表示由最大 2j 最小 20 组成 2i 的方案数即可,
注意题目没有mo,要用高精度!
复杂度:
O(n3∗高精度)
Code
标程只加了
gi,j,k=gi−1,j−1,k−1
的优化,所以很丑QwQ而且还要卡常QwQ:
#include <cstdio>
#include <cstdlib>
#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 max(q,w) ((q)>(w)?(q):(w))
using namespace std;
typedef long long LL;
const int N=102,YW=1000000000,YW1=9;
int m,n;
int a[N],z[N];
struct qqww
{
int n;
int a[151];
}f[2][N],g[2][N][N],LIN,YI,t;
int ss(int w)
{
if(!a[0])return 0;
int q=0;
fod(i,a[0],1)
{
a[i]+=q*10;
q=a[i]&1;a[i]>>=1;
}
if(!a[a[0]])a[0]--;
int OU=q;
q=ss(w+1)+1;
z[w]=OU;
return q;
}
qqww s;
qqww operator * (qqww a,qqww b)
{
if((a.n<2&&a.a[1]==0))return a;
if((b.n<2&&b.a[1]==0))return b;
fo(i,1,s.n)s.a[i]=0;
s.n=a.n+b.n-1;
fo(i,1,a.n)
fo(j,1,b.n)
{
LL t=s.a[i+j-1]+(LL)a.a[i]*b.a[j];
s.a[i+j-1]=t%YW;
s.a[i+j]+=t/YW;
}
while(s.a[s.n+1])
{
s.n++;
s.a[s.n+1]+=s.a[s.n]/YW;
s.a[s.n]%=YW;
}
return s;
}
qqww operator + (qqww a,qqww b)
{
a.n=max(a.n,b.n);
fo(i,1,a.n)
{
a.a[i]+=b.a[i];
while(a.a[i]>=YW)
{
a.a[i+1]++;
a.a[i]-=YW;
}
}
while(a.a[a.n+1])
{
a.n++;
a.a[a.n+1]+=a.a[a.n]/YW;
a.a[a.n]%=YW;
}
return a;
}
int main()
{
char ch;
for(char ch=getchar();ch<='9'&&ch>='0';ch=getchar())a[++a[0]]=ch-48;
fo(i,1,a[0]/2)
{
int t=a[i];
a[i]=a[a[0]-i+1];
a[a[0]-i+1]=t;
}
n=ss(1);
g[0][1][1].n=g[0][1][1].a[1]=1;
fo(i,1,n)f[0][i].n=f[0][i].a[1]=1;
bool nw=1,nwg=1;
fo(i,2,n)
{
fo(I,1,g[nwg][i][i].n)g[nwg][i][i].a[I]=0;
g[nwg][i][i].n=g[nwg][i][i].a[1]=1;
fo(I,1,g[nwg][1][1].n)g[nwg][1][1].a[I]=0;
g[nwg][1][1].n=g[nwg][1][1].a[1]=1;
fo(j,2,i-1)fo(k,2,j)
{
fo(I,1,max(g[nwg][j][k].n,g[!nwg][j-1][k-1].n))g[nwg][j][k].a[I]=g[!nwg][j-1][k-1].a[I];
g[nwg][j][k].n=g[!nwg][j-1][k-1].n;
}
fo(j,1,i-1)
{
fo(I,1,max(t.n,g[!nwg][1][1].n))t.a[I]=g[!nwg][1][1].a[I];
t.n=g[!nwg][1][1].n;
g[nwg][j][1]=(g[!nwg][j][1]*t);
fo(k,2,j)
{
t=t+g[!nwg][k][1];
g[nwg][j][1]=g[nwg][j][1]+g[!nwg][j][k]*t;
}
}
if(z[i])
{
fo(j,1,n)
{
fo(I,1,max(f[nw][j].n,f[nw][j-1].n))f[nw][j].a[I]=f[nw][j-1].a[I];
f[nw][j].n=f[nw][j-1].n;
fo(k,1,n)
f[nw][j]=f[nw][j]+g[nwg][j][k]*f[!nw][k];
}
nw=!nw;
}
nwg=!nwg;
}
printf("%d",f[!nw][n].a[f[!nw][n].n]);
fod(i,f[!nw][n].n-1,1)printf("%09d",f[!nw][n].a[i]);
printf("\n");
return 0;
}