1. 程式人生 > >51Nod 1383&1048 整數分解為2的冪

51Nod 1383&1048 整數分解為2的冪

題目

任何正整數都能分解成2的冪,給定整數N,求N的此類劃分方法的數量。
V1:n106。要對答案模1e9+7
V2:n1030。將整個答案輸出。

解題思路

考慮每一種劃分方法的序列是怎樣從一個空的序列變來的。
顯然,它是要麼+1,要麼集體乘2
因此很快樂地得出F[x]=F[x1]+F[x/2][x%2==0]
當然,如果要與V2接軌,那麼要換一種思路。
考慮將n轉換為二進位制,則n=Σ2x
因此,如果知道每個2i劃分為2的冪的和的方案數,那麼這題就很好做了。
對於某個

2i的一種劃分方案,如果不是隻有它本身一個數,一定可以把這些2的冪按照升序排序,然後分成兩段,每一段的和都是2i1
g[i][j]表示做完了2進位制下的前i位,最大的數為2j的方案數。
f[i][j]表示組成2i,最大的數為2j的方案數。
有人想到這樣的轉移方程:
g[i][j]=Σk=0jg[i1][k]f[i][j]
f[i][j]=Σk=0jf[i1][k]f[i1][j]
但是這樣會算重。
為了避免這,所以強制讓後面的數字大於等於
2k

所以將後面的數字都除以2k之後,可以得出這麼一個方程:
g[i][j]=Σk=0jg[i1][k]f[ik][jk]
f[i][j]=Σk=0jf[i1][k]f[i1k][jk]
顯然先預處理f
然後套上高精度,再卡常,就可以通過此題了。
卡常很重要,就是拿個longdouble,確定一下log2(n)
然而不知道為什麼,高精度壓8位WA了,壓9位就沒事?!

程式碼

#include<iostream>
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define N 100 #define M 150 #define mo 1000000000 #define fo(i,a,b) for(i=a;i<=b;i++) #define fd(i,a,b) for(i=a;i>=b;i--) using namespace std; struct note{ int w,a[M]; };note f[N][N],g[N][N],ans,n,c; int i,j,k,l,ys,x,tot; int xx; char s[32]; double x1,x2,x3; note operator + (const note &a,const note &b){ c.w=a.w>b.w?a.w:b.w; memset(c.a,0,sizeof(c.a)); int i; fo(i,1,c.w){ c.a[i]+=a.a[i]+b.a[i]; c.a[i+1]+=c.a[i]/mo;