卧薪尝胆,厚积薄发。
整数分解为2的幂 V2
Date: Tue Aug 28 08:29:11 CST 2018
In Category:
NoCategory
Description:
求
$n$
划分成二的整次幂的方案数。
$1\le n \le 10^{30}$
Solution:
一个二的次幂分解成二的次幂,一定是把他拆成两个小一的二的次幂。
设
$f[i][l][r]$
表示把
$2^i$
分解成最大
$2^l$
,最小
$2^r$
的方案数。
$\begin{align}f[i][l][r]=\sum_{k=l}^r f[i-1][l][k]\times f[i-1][k][r]\end{align}$
,因为相同拆分算同一种方案,所以假设左边的都比右边大。
但是由于有
$f[i][l][r]=f[i-1][l-1][r-1]$
,所以只用保存
$f[i][l][0]$
,于是
$f[i][j]$
表示把
$2^i$
分解为最大为
$2^j$
的方案数。即
$\begin{align}f[i][l][0]=\sum_{k=l}^r f[i-1][l][k]\times f[i-1][k][0]\end{align}$
,由于前半部分要求大于
$k$
,就整体除掉
$k$
,即
$f[i-1][l][k]=f[i-k-1][l-k][0]$
,于是
$f$
转移为
$\begin{align}f[i][j]=\sum_{k=0}^jf[i-1][k]\times f[i-j-1][k-j]\end{align}$
。
然后问题是怎么统计答案,先把
$n$
二进制分解,设
$g[i][j]$
表示做完了
$n$
的二进制的前
$i$
个一,最大数是
$2^j$
的方案数,有转移
$\begin{align}g[i][j]=\sum_{k=0}^jg[i-1][k]\times f[w][j][k]\end{align}$
,思路与之前相似,还是保证新产生的比之前分解的都大,
$w$
是
$i$
这位所代表的
$2$
的指数,先之前一样
$f[w][j][k]=f[w-k][j-k][0]$
。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#pragma GCC optimize(3)
using namespace std;
#define BASE 1000000000
typedef long long ll;
#define MAXN 99
struct bigint
{
int w,a[170];
bigint(){w = 0;memset(a,0,sizeof(a));}
friend bigint operator + (bigint a,bigint b)
{
register bigint t;
t.w = max(a.w,b.w);
for(register int i = 1;i <= t.w;++i)
{
t.a[i] += a.a[i] + b.a[i];
if(t.a[i] >= BASE)
{
t.a[i + 1] = 1;
t.a[i] -= BASE;
}
}
if(t.a[t.w + 1] > 0)++t.w;
return t;
}
friend bigint operator * (bigint a,bigint b)
{
register bigint t;
for(register int i = 1;i <= a.w;++i)
{
for(register int j = 1;j <= b.w;++j)
{
t.a[i + j] += ((ll)t.a[i + j - 1] + (ll)a.a[i] * (ll)b.a[j]) / BASE;
t.a[i + j - 1] = ((ll)t.a[i + j - 1] + (ll)a.a[i] * (ll)b.a[j]) % BASE;
}
}
for(t.w = a.w + b.w;t.w > 1 && t.a[t.w] == 0;--t.w);
return t;
}
}f[MAXN + 5][MAXN + 5],ans,n,s[MAXN + 5],g[MAXN + 5][MAXN + 5];
char c[170];
int main()
{
scanf("%s",c + 1);
register int l = strlen(c + 1);
n.w = l / 9 + 1;
for(register int i = 1;i <= l;++i)
{
register int j = (l - i) / 9;
n.a[j + 1] = n.a[j + 1] * 10 + c[i] - '0';
}
f[0][0].w = f[0][0].a[1] = 1;
for(register int i = 1;i <= MAXN;++i)
{
for(register int j = 0;j < i;++j)
{
for(register 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;
}
register int tot = 0;
for(register int i = 0;i <= MAXN;++i)
{
if(n.a[1] & 1)
{
++tot;
if(tot == 1)
{
for(register int j = 0;j <= i;++j)g[1][j] = f[i][j];
}
else
{
for(register int j = 0;j <= i;++j)
{
for(register int k = 0;k <= j;++k)
{
g[tot][j] = g[tot][j] + g[tot - 1][k] * f[i - k][j - k];
}
}
}
}
register int r = 0;
for(register int j = n.w;j >= 1;--j)
{
register int t = n.a[j];
n.a[j] = ((ll)r * BASE + t) / 2;
r = ((ll)r * BASE + t) % 2;
}
}
for(register int i = 0;i <= MAXN;++i)ans = ans + g[tot][i];
printf("%d",ans.a[ans.w]);
for(register int i = ans.w - 1;i;i--)
{
for(register int j = BASE / 10;j >= 1;j /= 10)
{
putchar('0' + (ans.a[i] / j));
ans.a[i] %= j;
}
}
puts("");
return 0;
}
In tag:
DP-DP
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡