1. 程式人生 > >[51Nod 1048] 整數分解為2的冪 V2

[51Nod 1048] 整數分解為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+2+2
=1+2+2+2
=1+1+1+4
=1+2+4
(1 <= N <= 10^30)

Solution

O(N)的做法十分顯然。
f[i]=f[i1]+f[i/2],當i為偶數
f[i]=f[i1] 當i為奇數。

既然N這麼大了,考慮log 做法
假定N=2p
似乎它與2p

1有一定關係。

f[i][l][r]表示做到2i,當前分解最大的數是2r,最小的是2l
這樣很好的避免了重複問題。
顯然f[i][l][r]=k=lrf[i1][l][k]f[i1][k][r]

log4N似乎有點大。
事實上,f[i][l][r]=f[i1][l1][r1](即分解的所有數同時除以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]); } }

相關推薦

[51Nod 1048] 整數分解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+2+2

51Nod 1383&1048 整數分解2

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

51nod 1383 整數分解2(數列,也可以自己根據觀察找規律推理得到遞推公式)

描述: 組合數學生成函式 1383 整數分解為2的冪 1 秒   131,072 KB   80 分   5 級題 任何正整數都能分解成2的冪,給定整數N,求N的此類劃分方法的數量!由於方案數量較大,輸出

51Nod-1383-整數分解2

ACM模版 描述 題解 看到這裡,我們應該可以想到,這是一個數論問題,應該是一個什麼數列,暴力解出來小資料後,在 OEIS 中查看了一下下,發現的確是一個十分有趣的數列——Binary partition function: number of p

[51nod1383&1048]整數分解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+2 =1+1+1+4

51nod 1383 整數分解2(遞推)

Description 任何正整數都能分解成2的冪,給定整數N,求N的此類劃分方法的數量!由於方案數量較大,輸出Mod 1000000007的結果。 比如N = 7時,共有6種劃分方法。 7=1+1+1+1+1+1+1 =1+1+1+1+1+2

51nod 1383 整數分解2

#include<bits/stdc++.h> using namespace std; const int MAXN=1000100; const int mod=1e9+7; int

[51Nod 1383] 整數分解2

Description 任何正整數都能分解成2的冪,給定整數N,求N的此類劃分方法的數量!由於方案數量較大,輸出Mod 1000000007的結果。 比如N = 7時,共有6種劃分方法。

51nod-1383 整數分解2

原題連結  收藏  關注 任何正整數都能分解成2的冪,給定整數N,求N的此類劃分方法的數量!由於方案數量較大,輸出Mod 1000000007的結果。 比如N = 7時,共有6

51NOD 1383】整數分解2

DH ---------以上初三THU/PKU大爺---- Alan_cty LYD XHM HZJ ZZ ---以下是大神%-- YMW Samjia2000 werkeytom_ftd Crazy_czy WorldWide_D Yxuan

[51nod1138]正整數分解幾個連續自然數之和

sqrt esp 連續 奇數 mes 判斷 -i 兩個 註意 解題關鍵:註意為什麽上界是$\sqrt {2n} $ 因為函數是關於m的遞減函數,而結果必須為正整數 $a = \frac{{2n + m - {m^2}}}{{2m}} = \frac{n}{m} + \f

PTA7-37 整數分解若干項之和(20 分)超級詳解

將一個正整數N分解成幾個正整數相加,可以有多種分解方法,例如7=6+1,7=5+2,7=5+1+1,…。程式設計求出正整數N的所有整數分解式子。輸入格式:每個輸入包含一個測試用例,即正整數N (0<N≤30)。輸出格式:按遞增順序輸出N的所有整數分解式子。遞增順序是指:

一個正整數分解幾個連續的正整數之和

題目: 給定你一個數字 如:15 15可分解為 7+8 4+5+6 1+2+3+4+5 再如: 8 8不可分解為任何連續的正整數之和 所以輸出NONE 此題就是給定一個數字如果這個數字可以分解為

7-37 整數分解若干項之和(20 分)

題目連結(組合版):點選開啟連結題目大意:略。解題思路:此方法僅限於輸出組合情況,計數的話會TLE。附加題目(計數版):點選開啟連結AC 程式碼(組合版)#include<bits/stdc++.

PTA 7-12 整數分解若干項之和(20 分)

將一個正整數N分解成幾個正整數相加,可以有多種分解方法,例如7=6+1,7=5+2,7=5+1+1,…。程式設計求出正整數N的所有整數分解式子。 輸入格式: 每個輸入包含一個測試用例,即正整數N (0 < N ≤ 30)。 輸出格式: 按遞增順序輸出N的所有整數分解式

整數分解n個連續正整數

思路:等差數列求和: sn=a1*n+n*(n-1)*d/2 在這裡d為1 #include<stdio.h> //#define N 1000 #define M 10 void print(int k) {int sn=0,t=0;for(int a1=1;

7-1 整數分解若干項之和(20 分)(dfs)

思路:不帶標記的dfs,只要沒有超過和就不斷dfs直到超過了之後向前回溯。 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math

(PTA)7-1 整數分解若干項之和

題目 將一個正整數N分解成幾個正整數相加,可以有多種分解方法,例如7=6+1,7=5+2,7=5+1+1,…。程式設計求出正整數N的所有整數分解式子。 輸入格式: 每個輸入包含一個測試用例,即正整數N (0 輸出格式: 按遞增順

pta 5-37 整數分解若干項之和 (遞迴)

5-37 整數分解為若干項之和   (20分) 將一個正整數N分解成幾個正整數相加,可以有多種分解方法,例如7=6+1,7=5+2,7=5+1+1,…。程式設計求出正整數N的所有整數分解式子。 輸入格式: 每個輸入包含一個測試用例,即正整數N (0<<

面試總結:任意一個整數分解幾個連續正整數之和

       前陣子參加了國內某一大公司的面試。到了之後,人家不問出身,不問來歷,就直接開機讓我上機程式設計。因為是第一次在面試時上機操作,儘管題目不是很難,但是由於沒搞清楚機考和筆試的區別,導致最後面試失敗。現在總結一下自己在機考時碰到的一些問題,以免自己以後再犯同樣的錯