1. 程式人生 > >【LG4317】花神的數論題

【LG4317】花神的數論題

【LG4317】花神的數論題

題面

洛谷

題解

\(f_{i,up,tmp,d}\)表示當前在第\(i\)位,是否卡上界,有\(tmp\)個一,目標是幾個一的方案數
最後將所有\(d\)固定,套數位\(dp\)的板子
然後快速冪乘起來就好了
程式碼

#include <iostream> 
#include <cstdio>
#include <cstdlib>
#include <cstring> 
#include <cmath> 
#include <algorithm>
#include <vector> 
using namespace std;
#define int long long 
const int Mod = 1e7 + 7; 
int N, f[55][2][55][55];
vector<int> digit;
int fpow(int x, int y) {
    int res = 1;
    while (y) {
        if (y & 1) res = 1ll * res * x % Mod; 
        x = 1ll * x * x % Mod;
        y >>= 1ll; 
    }
    return res; 
} 
int dfs(int o, bool up, int tmp, int d) { 
    if (o == -1) return tmp == d; 
    if (~f[o][up][tmp][d]) return f[o][up][tmp][d]; 
    int lim = up ? digit[o] : 1, res = 0; 
    for (int i = 0; i <= lim; i++) res = res + dfs(o - 1, up && i == lim, tmp + (i == 1), d); 
    return f[o][up][tmp][d] = res; 
}
int ans[100]; 
int solve(int n) { 
    while (n) digit.push_back(n & 1ll), n >>= 1ll;
    digit.push_back(0); 
    for (int i = 1; i <= 50; i++) {
        memset(f, -1, sizeof(f)); 
        ans[i] = dfs(digit.size() - 1, 1, 0, i); 
    } 
    int res = 1;
    for (int i = 1; i <= 50; i++) res = 1ll * res * fpow(i, ans[i]) % Mod;
    return res; 
} 
signed main () {
    cin >> N; 
    printf("%lld\n", solve(N)); 
    return 0; 
}