hihocoder 1259 (数位DP)

连接:点击打开链接

题意:定义g(x)为f(1)到f(n)中模k余n的个数,求出所有g(x)的异或和.

坑爹UVA一直报RE然后转向hihocoder就过了~

f(2x)=3f(x),f(2x+1)=f(2x)+1.

然后发现f(1)到f(n)在三进制下等价于二进制下的1到n,然后就可以用数位DP搞了.

这个思想下的转移方程dp(d,m) = dp(d-1, (m-x)%k).

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;

long long dp[68][68686];
long long n, ans[68686];
int mod;
int bit[68], l;
#define pow Pow
long long pow[68];

void solve (long long num) {
    long long cur = 1;
    l = 0;
    while (num) {
        bit[++l] = (num&1);
        num >>= 1;
    }
    pow[0] = 1;
    for (int i = 1; i <= l; i++) pow[i] = pow[i-1]*3%mod;
    for (int i = 1; i <= l; i++, cur *= 3, cur %= mod) {
        for (int j = 0; j < mod; j++) {
            dp[i][(j+cur)%mod] += dp[i-1][j];//1
            dp[i][j] += dp[i-1][j];//0
        }
    }
    memset (ans, 0, sizeof ans);
    cur = 0;
    for (int i = l; i >= 1; i--) {
        if (bit[i]) {
            for (int j = 0; j < mod; j++) {
                ans[(j+cur)%mod] += dp[i-1][j];
            }
            cur += pow[i-1]%mod;
            cur %= mod;
        }
    }
    ans[cur]++;//最终的数字
    ans[0]--;//排除数字0
    long long gg = 0;
    for (int i = 0; i < mod; i++) {
        gg ^= ans[i];
    } 
    cout << gg << endl;
    return ;
}

int main () {
    //freopen ("in.txt", "r", stdin);
    int t;
    scanf ("%d", &t);
    while (t--) {
        memset (dp, 0, sizeof dp);
        dp[0][0] = 1;
        scanf ("%lld%d", &n, &mod);
        solve (n);
    }
    return 0;
}


你可能感兴趣的:(hihocoder 1259 (数位DP))