51 nod 1048 整数分解为2的幂 V2

传送门.

题解:

把n转成二进制,设二进制下是1的位是x1、x2…xm。

结论:
把一种分解方案按升序排序,则一定可以从左到右划分成2^x1,2^x2……2^xm

证明很显然。

于是设 g i , j 表示搞到了xi,当前最大的是2^j的方案数。

f i , j 表示把2^i分解,最大的是2^j的方案数。

转移:

g i , j = k = 1 j g i 1 , k f x i k , j k

如何求f,f有个类似的结论。

就是2^i的一种分解,按照升序排序,一定可以划分成 2 i 1 + 2 i 1

所以 f i , j = k = 0 j f i 1 , k f i 1 k , j k ]

高精度往死里卡常:

比如加法的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);
}

猜你喜欢

转载自blog.csdn.net/cold_chair/article/details/80889334