题解:
把n转成二进制,设二进制下是1的位是x1、x2…xm。
结论:
把一种分解方案按升序排序,则一定可以从左到右划分成2^x1,2^x2……2^xm
证明很显然。
于是设 表示搞到了xi,当前最大的是2^j的方案数。
设 表示把2^i分解,最大的是2^j的方案数。
转移:
如何求f,f有个类似的结论。
就是2^i的一种分解,按照升序排序,一定可以划分成
所以
高精度往死里卡常:
比如加法的mo变成if,用long long压9位。
Code:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
#define mem(a) memset(a, 0, sizeof a)
#define max(a, b) ((a) > (b) ? (a) : (b))
using namespace std;
const int M = 1e9;
char s[50]; int len;
int num[50], x[100];
struct node {
int l; ll a[150];
} a, g[101][100], f[100][100], c, ans;
void plus(node &a, node &b) {
a.l = max(a.l, b.l);
fo(i, 1, a.l) {
a.a[i] += b.a[i];
if(a.a[i] > M) a.a[i] -= M, a.a[i + 1] ++;
}
while(a.a[a.l + 1]) a.l ++;
}
void prod(node &a, node &b) {
c.l = a.l + b.l - 1; mem(c.a);
fo(i, 1, a.l) {
fo(j, 1, b.l) {
c.a[i + j - 1] += a.a[i] * b.a[j];
c.a[i + j] += c.a[i + j - 1] / M;
c.a[i + j - 1] %= M;
}
}
while(c.a[c.l + 1]) c.l ++;
}
void write(const node &a) {
printf("%lld", a.a[a.l]);
fd(i, a.l - 1, 1) printf("%09lld", a.a[i]);
printf("\n");
}
int main() {
scanf("%s", s + 1); len = strlen(s + 1);
fo(i, 1, len / 2) swap(s[i], s[len - i + 1]);
fo(i, 1, len) num[i] = num[i - 1] + (i % 9 == 1);
a.l = num[len]; fd(i, len, 1) a.a[num[i]] = a.a[num[i]] * 10 + s[i] - '0';
int tp = -1;
while(!(a.l == 1 && a.a[1] == 0)) {
ll y = 0;
fd(i, a.l, 1) a.a[i] += y * 1e9, y = a.a[i] % 2, a.a[i] /= 2;
while(a.l > 1 && a.a[a.l] == 0) a.l --;
++ tp; if(y) x[++ x[0]] = tp;
}
fo(i, 0, tp) {
fo(j, 0, i - 1) {
f[i][j].l = 1; f[i][j].a[1] = 0;
fo(k, 0, j) {
prod(f[i - 1][k], f[i - 1 - k][j - k]);
plus(f[i][j], c);
}
}
f[i][i].l = f[i][i].a[1] = 1;
}
g[0][0].l = 1; g[0][0].a[1] = 1;
fo(i, 1, x[0]) {
fo(j, 0, x[i]) {
g[i][j].l = 1; mem(g[i][j].a);
fo(k, 0, j) {
if(g[i - 1][k].l == 0) continue;
prod(g[i - 1][k], f[x[i] - k][j - k]);
plus(g[i][j], c);
}
}
}
ans.l = 1; ans.a[1] = 0;
fo(j, 0, x[x[0]]) plus(ans, g[x[0]][j]);;
write(ans);
}