【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; 
} 
posted @ 2019-01-05 16:58  heyujun  阅读(263)  评论(0编辑  收藏  举报