The 2015 ACM-ICPC Asia Beijing Regional Contest K A Math Problem

来源:互联网 发布:mysql dump 导出表 编辑:程序博客网 时间:2024/05/21 09:56

思路:

经过分析可得:
f(2 * k) = 3 * f(k)
f(2 * k + 1) = 3 * f(k) + 1

然后:f(x) = 把x用二进制表示出来后,用三进制来计算得到的数值

如:x = 5时,二进制为101,所以f(5) = 1 * 3^2 + 0 * 3^1 + 1 * 3^0 = 10

有了这个之后我们把1~n的数,变成二进制,写成一列,比如n = 5类似这个样子:

000

001

010

011

100

101

然后我们发现其实可以dp搞定这道题,dp[i][j],其中i表示dp到第i个二进制位的时候,mod = j有多少个数,然后就是计算1~n的数在某一位二进制位上的0和1的个数,进行转移,大概这个样子。


skt的代码,不是我写的

#include <bits/stdc++.h>using namespace std;#define LL long long#define MAXN 65540int T;LL N, K, g[64][2][MAXN], tmp[MAXN], t[64];void work() {    scanf("%lld %lld", &N, &K);    if (N == 1) {        cout << 1 << endl;         return ;    }    if (K == 3) {        LL p1 = N / 2, p2 = N - p1;        cout << (p1 ^ p2) << endl;         return ;    }    memset(tmp, 0, sizeof(tmp));    memset(g[0], 0, sizeof(g[0]));    g[0][0][0] ++;    g[0][1][1 % K] ++;    LL three = 1LL;    int bit = 0;    t[0] = 1;    for (int i = 1; (1ll << i) <= N; i ++) {        bit = max(bit, i);        fill(g[i][0], g[i][0] + K + 1, 0);        fill(g[i][1], g[i][1] + K + 1, 0);        three *= 3LL;        three %= K;        t[i] = three;        for (int j = 0; j < K; j ++) {            g[i][1][(j + three) % K] += g[i - 1][0][j];            g[i][1][(j + three) % K] += g[i - 1][1][j];        }        for (int j = 0; j < K; j ++) {            g[i][0][j] += g[i - 1][0][j];            g[i][0][j] += g[i - 1][1][j];        }    }    LL add = 0LL;    for (int i = bit; i >= 0; i --) {        if (N & (1ll << i)) {            for (int j = 0; j < K; j ++) {                tmp[(j + add) % K] += g[i][0][j];             }            add += t[i];        }    }    tmp[add % K] ++;    tmp[0] --;    LL res = 0LL;    for (int i = 0; i < K; i ++) {        res ^= tmp[i];    }    cout << res << endl;}int main() {#ifdef __SKT__    freopen("in", "r", stdin);#endif    scanf("%d", &T);    while (T --) {        work();    }    return 0;}


0 0