P4317 花神的数论题(数位dp)

目录

Description

\(sum(i)\) 代表 \(i\) 的二进制数中 \(1\) 的个数,求 \(\prod_{i=1}^n sum(i)\)

State

\(mod = 10^7+7\)

\(1<=n<=10^{15}\)

Input

3

Output

2

Solution

因为需要知道 \(sum(1), sum(2), ....sum(n)\) 的值,\(O(n)\) 的方法肯定是不行的,所以需要另辟蹊径,如果可以计算出包含 \(i\)\(1\)\(sum()\) 的个数,利用快速幂可以解决这个问题

剩下的还是老样子,\(dp[pos][sum]\) 表示到达 \(pos\) 位置处,已经有 \(sum\)\(1\) 时拥有 \(sum()\) 的个数,但是这样还不够好,因为需要多次初始化,不放在加一维表示所需要 \(1\) 的个数

Code

ll mod = 1e7 + 7;

    ll n, m, _;
    int i, j, k;
    int a[55];
    int tot;
    ll dp[55][55][55];

ll pow_mod(ll a, ll x)
{
    ll ans = 1;
    while(x){
        if(x & 1) ans = ans * a % mod;
        a = (a * a) % mod;
        x >>= 1;
    }
    return ans;
}

ll reap(ll &x)
{
    x %= mod;
    x += mod;
    x %= mod;
    return x;
}

ll dfs(int pos, int sum, bool top, int all)
{
    if(! pos) return (sum == all);
    if(! top && dp[pos][sum][all] != -1) return dp[pos][sum][all];
    int up = 1; ll ans = 0;
    if(top) up = a[pos];
    for(int i = 0; i <=  up; i ++){
        ans += dfs(pos - 1, sum + (i == 1), top & (i == up), all);
    }
    if(!top) dp[pos][sum][all] = ans;
    return ans;
}

ll solve(ll x)
{
    tot = 0;
    while(x) a[++ tot] = x & 1, x >>= 1;
    ll bit[55] = {0}, ans = 1;
    ms(dp, -1);
    for(int i = 1; i <= 50;i ++){
        bit[i] = dfs(tot, 0, 1, i);
        ans *= pow_mod(i, bit[i]);
        reap(ans);
    }
    return ans;
}

signed main()
{
    //IOS;
    while(~ sll(n)){
        pll(solve(n));
    }
    return 0;
}

P4317 花神的数论题(数位dp)

上一篇:精准计算年龄到天数


下一篇:lodash合并两个数组中去重的对象