[BZOJ1223][HNOI2002]Kathy函数(数位DP/乱搞)

首先,在二进制意义下, f(n) n 的各位数翻转,即f((a1a2...ax1ax¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯)2)=(axax1...a2a1¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯)2
网上好多题解里都没有给出上面命题的具体证明,所以这里就给出清华爷InvUsr的证明过程吧(以下的证明过程中的数位全部为二进制意义, n n 在二进制意义下的各位数翻转)。
基本思想是数学归纳法。首先,可以发现n 1,2,3 时原命题都成立。
第一个递推式: f(2n)=f(n)
n=a1a2...ax1ax¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ ,那么 2n=a1a2...ax1ax0¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ 。显然有 n=(2n) (去掉前导 0 )。所以当f(n)=n时一定有 f(2n)=(2n)
第二个递推式: f(4n+1)=2f(2n+1)f(n)
n=a1a2...ax1ax¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ ,那么 2n+1=a1a2...ax1ax1¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ 4n+1=a1a2...ax1ax01¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
显然,
2(2n+1)n=1axax1...a2a1¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯+1axax1...a2a1¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯axax1...a2a1¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
=10axax1...a2a1¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯=(4n+1)
也就是说,当 f(2n+1)=(2n+1),f(n)=n 时, f(4n+1)=(4n+1)
第三个递推式: f(4n+3)=3f(2n+1)2f(n)
还是设 n=a1a2...ax1ax¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ 。此时有:
2n=axax1...a2a10¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
(2n+1)=1axax1...a2a1¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
(4n+3)=11axax1...a2a1¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
3(2n+1)2n=1axax1...a2a1¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯+1axax1...a2a1¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯+1axax1...a2a1¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯axax1...a2a10¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
=11axax1...a2a1¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯+axax1...a2a10¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯axax1...a2a10¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
=11axax1...a2a1¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯=(4n+3)
也就是说,当 f(2n+1)=(2n+1),f(n)=n 时, f(4n+3)=(4n+3)
归纳得出,对于任意一个 n1 f(n)=n
也就是说, f(n)=n 的充分必要条件是 n 在二进制意义下是回文串。
m化为二进制之后数位DP或者乱搞。
代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 605;
struct cyx {
    int n, a[N];
    cyx() {}
    cyx(int _n) :
        n(_n) {memset(a, 0, sizeof(a));}
} a, b, f[N], g[N];
cyx read() {
    int i = 1, j; cyx res = cyx(0); char c; bool flag = 0;
    while ((c = getchar()) < '0' || c > '9');
    if (c - 48) res.a[res.n = 1] = c - 48, flag = 1;
    while ((c = getchar()) >= '0' && c <= '9') {
        if (c - 48) flag = 1;
        if (flag) res.a[++res.n] = c - 48;
    }
    if (!res.n) res.a[res.n = 1] = 0;
    for (j = res.n; i < j; i++, j--) swap(res.a[i], res.a[j]);
    return res;
}
void write(cyx num) {
    int i; for (i = num.n; i; i--) putchar(num.a[i] + 48);
    putchar('\n');
}
cyx div2(cyx a) {
    int i; cyx b = a;
    for (i = b.n; i; i--) {
        if (b.a[i] & 1) b.a[i - 1] += 10;
        b.a[i] >>= 1;
    }
    while (b.n > 1 && !b.a[b.n]) b.n--;
    return b;
}
cyx add(cyx a, cyx b) {
    int i; cyx c = cyx(max(a.n, b.n));
    for (i = 1; i <= c.n; i++) {
        c.a[i] += a.a[i] + b.a[i];
        if (c.a[i] > 9) c.a[i + 1]++, c.a[i] -= 10;
    }
    if (c.a[c.n + 1]) c.n++; return c;
}
cyx pow2(int x) {
    int i, j, tmp; cyx res = cyx(1); res.a[1] = 1;
    for (i = 1; i <= x; i++) {
        tmp = 0;
        for (j = 1; j <= res.n; j++) {
            res.a[j] <<= 1; res.a[j] += tmp;
            if (res.a[j] > 9) res.a[j] -= 10, tmp = 1;
            else tmp = 0;
        }
        if (tmp) res.a[++res.n] = 1;
    }
    return res;
}
cyx plus1(cyx x) {
    int i = 1;
    while (i <= x.n && x.a[i] == 9) x.a[i++] = 0;
    if (i > x.n) x.a[++x.n] = 1; else x.a[i]++;
    return x;
}
cyx trans(cyx x) {
    int i; cyx res = cyx(1);
    for (i = 1; i <= x.n; i++)
        if (x.a[i]) res = add(res, pow2(i - 1));
    return res;
}
cyx solve(cyx v) {
    if (v.n == 1 && v.a[1] == 1) return pow2(0);
    f[0] = pow2(0);
    int i, j, k, h, n = v.n; for (i = 1; i <= v.n; i++)
        f[i] = pow2(i & 1 ? (i >> 1) + 1 : i >> 1),
        g[i] = i == 1 ? pow2(0) : f[i - 2];
    if (v.n & 1) {
        for (i = j = (v.n >> 1) + 1; j <= v.n; i--, j++)
            if (v.a[i] != v.a[j]) break;
        if (i) {
            if (v.a[i] > v.a[j]) for (k = h = (v.n >> 1) + 1; h <= v.n; k--, h++)
                v.a[k] = v.a[h];
            else {
                if (v.a[(v.n >> 1) + 1]) {
                    v.a[(v.n >> 1) + 1] = 0;
                    for (k = h = (v.n >> 1) + 1; h <= v.n; k--, h++)
                        v.a[k] = v.a[h];
                }
                else {
                    bool flag = 1;
                    for (k = 1; k < v.n; k++) if (v.a[k]) {flag = 0; break;}
                    if (flag) {
                        v.a[v.n--] = 0;
                        for (k = 1; k <= v.n; k++) v.a[k] = 1;
                    }
                    else {
                        k = (v.n >> 1) + 1;
                        while (!v.a[k]) v.a[k++] = 1; v.a[k]--;
                        for (i = 1; i <= (v.n >> 1); i++)
                            v.a[i] = v.a[v.n - i + 1];
                    }
                }
            }
        }
    }
    else {
        for (i = (v.n >> 1), j = (v.n >> 1) + 1; j <= v.n; i--, j++)
            if (v.a[i] != v.a[j]) break;
        if (i) {
            if (v.a[i] > v.a[j])
            for (k = (v.n >> 1), h = (v.n >> 1) + 1; h <= v.n; k--, h++)
                v.a[k] = v.a[h];
            else {
                bool flag = 1;
                for (k = 1; k < v.n; k++) if (v.a[k]) {flag = 0; break;}
                if (flag) {
                    v.a[v.n--] = 0;
                    for (k = 1; k <= v.n; k++) v.a[k] = 1;
                }
                else {
                    k = (v.n >> 1) + 1;
                    while (!v.a[k]) v.a[k++] = 1; v.a[k]--;
                    for (i = 1; i <= (v.n >> 1); i++)
                        v.a[i] = v.a[v.n - i + 1];
                }
            }
        }
    }
    cyx res = cyx(1); for (i = 1; i < n; i++) res = add(res, g[i]);
    if (n != v.n) return res; int mid = (n & 1) ? (n >> 1) + 1 : (n >> 1);
    cyx uu = cyx(0); for (i = mid; i >= 2; i--) uu.a[++uu.n] = v.a[i];
    while (uu.n > 1 && !uu.a[uu.n]) uu.n--; cyx vv = plus1(trans(uu));
    return add(res, vv);
}
int main() {
    a = read(); b = cyx(0);
    while (a.n != 1 || a.a[1]) b.a[++b.n] = a.a[1] & 1,
        a = div2(a); write(solve(b));
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值