[BZOJ 3209] 花神的数论题
[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=3209
[算法]
数位DP
记f[i][j][k]表示i位, 最高为为j , 有k个1的二进制数有多少个
然后 , 计算1-N中 , 出现i个1的数有多少个
用快速幂将答案乘起来 , 即可
[算法]
#include<bits/stdc++.h> using namespace std; typedef long long LL; const LL MAXN = 1e15 + 10; const int MAXLOG = 50; const int P = 10000007; LL n; LL ans[MAXLOG + 10]; LL f[MAXLOG + 10][2][MAXLOG + 10]; template <typename T> inline void chkmin(T &x , T y) { x = min(x , y); } template <typename T> inline void chkmax(T &x , T y) { x = max(x , y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline void preprocess() { f[1][0][0] = f[1][1][1] = 1; for (int i = 1; i < MAXLOG; i++) { for (int j = 0; j < 2; j++) { for (int k = 0; k <= i; k++) { f[i + 1][1][k + 1] += f[i][j][k]; f[i + 1][0][k] += f[i][j][k]; } } } } inline void calc(LL n) { int len = 0; static int a[MAXLOG]; LL ret = 0; while (n > 0) { a[++len] = n & 1; n >>= 1; } reverse(a + 1 , a + len + 1); int cnt = 0; for (int i = 1; i <= len; i++) { if (a[i] == 1) { for (int j = 0; j <= len - i + 1; j++) ans[cnt + j] += f[len - i + 1][0][j]; ++cnt; } else continue; } } inline int exp_mod(LL a , LL n) { LL res = 1 , b = a; while (n > 0) { if (n & 1) res = 1LL * res * b % P; b = 1LL * b * b % P; n >>= 1; } return res; } int main() { preprocess(); read(n); calc(n + 1); int res = 1; for (int i = 1; i < MAXLOG; i++) res = 1LL * res * exp_mod(i , ans[i]) % P; printf("%d\n" , res); return 0; }