P4317 花神的数论题

题意简述

( ext{sum}(i))(i)的二进制中(1)的个数,求

[prod_{i = 1} ^ n ext{sum}(i) ]

(n le 10 ^ {15})

简单口胡

考虑对每个数求( ext{sum}(i))肯定是不行的,只能考虑将思维转到求“有多少数的( ext{sum}(i) = x),然后对(x)进行操作,因为( ext{sum}(i))的最大值也就(50)左右,大大降低复杂度。

具体地,考虑求出( ext{S}_i = sum_{k = 1} ^ n {[ ext{sum}(k) = i]}),答案即为

[prod_{i = 1} ^ {log{n}} i ^ { ext{S}_i} ]

考虑数位( ext{dp}),设( ext{dfs}(n,cnt,now))为当前在第(now)位,当前有(cnt)位为(1),目标要求(n)为为(1)的答案。

记忆化搜索,记得要反着搜。

别忘了必要的剪枝。

# include <bits/stdc++.h>
using namespace std;
long long x;
const long long mod = 10000007;

const int M = 52;

long long dp[M][M][M];

int N;
int a[M];
long long q[M];

long long dfs(int n,int cnt,int now,bool op)
{
    // printf("n = %d,cnt = %d,now = %d,op = %d
",n,cnt,now,op);
    if(now == -1) return cnt == n;
    if(cnt + now + 1 < n) return dp[n][cnt][now] = 0;
    if(!op && dp[n][cnt][now] != -1) return dp[n][cnt][now];
    int limit = (op == 1) ? a[now] : 1;
    long long ans = 0;
    for(int i = 0; i <= limit; i++)
    {
        ans = ans + dfs(n,cnt + (1 == i),now - 1,op && i == limit);
    }
    if(!op) dp[n][cnt][now] = ans;
    return ans;
}

long long qmulti(long long x,long long p)
{
    long long ans = 1;
    while(p)
    {
        if(p & 1) 
        {
            ans = (ans * x) % mod;
        }
        p >>= 1;
        x = (x * x) % mod;
    }
    return ans;
}

void solve(void)
{
    N = log2(x);
    for(int i = N; i >= 0; i--) 
    {
        if((x >> i) & 1) a[i] = 1;
    }
    // printf("N = %d
",N);
    // printf("Yes:chaifen
");
    N++;
    for(int i = N; i >= 1; i--)
    {
        memset(dp,-1,sizeof(dp));
        // printf("i = %d
",i);
        q[i] = dfs(i,0,N - 1,1);
        // printf("q[%d] = %lld
",i,q[i]);
    }
    // printf("Yes:q
");
    long long ans = 1;
    for(int i = N; i >= 1; i--)
    {
        ans = (ans * qmulti(i,q[i]))% mod;
    }
    printf("%lld
",ans);
}

int main(void)
{
    scanf("%lld",&x);
    solve();
    return 0;
}

原文地址:https://www.cnblogs.com/luyiming123blog/p/P4317.html