花神的数论题

Posted cj-xxz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了花神的数论题相关的知识,希望对你有一定的参考价值。

题面

题解

数位dp都是套路题

设$f[i][0/1][k][l]$表示$dp$到第$i$位,是否卡上界,现在$1$的个数为$k$,所求的$1$的个数为$l$的方案数

转移看一下代码吧,很好懂的。

$ecause10^7+7$不是质数,$ herefore;f$要开$ ext{long long}$

代码

#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<vector>
#define RG register
#define file(x) freopen(#x".in", "r", stdin);freopen(#x".out", "w", stdout);
#define clear(x, y) memset(x, y, sizeof(x))

#define int long long
inline int read()
{
	int data = 0, w = 1; char ch = getchar();
	while(ch != ‘-‘ && (!isdigit(ch))) ch = getchar();
	if(ch == ‘-‘) w = -1, ch = getchar();
	while(isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
	return data * w;
}

const int Mod(10000007);
int n;
long long f[60][2][60][60];
std::vector<int> dig;

inline int fastpow(int x, int y)
{
	int ans = 1;
	while(y)
	{
		if(y & 1) ans = 1ll * ans * x % Mod;
		x = 1ll * x * x % Mod, y >>= 1;
	}
	return ans;
}

int dfs(int x, int lim, int cnt, int max)
{
	if(x == -1) return cnt == max;
	if(~f[x][lim][cnt][max]) return f[x][lim][cnt][max];
	int newlim = lim ? dig[x] : 1, ans = 0;
	for(RG int i = 0; i <= newlim; i++)
		ans += dfs(x - 1, lim && newlim == i, cnt + (i == 1), max);
	return f[x][lim][cnt][max] = ans;
}

int ans[60];
int solve(int n)
{
	while(n) dig.push_back(n & 1), n >>= 1;
	dig.push_back(0);
	for(RG int i = 1; i <= 50; i++)
	{
		clear(f, -1);
		ans[i] = dfs(dig.size() - 1, 1, 0, i);
	}
	int tot = 1;
	for(RG int i = 1; i <= 50; i++) tot = 1ll * tot * fastpow(i, ans[i]) % Mod;
	return tot;
}

signed main()
{
	n = read();
	printf("%lld
", solve(n));
	return 0;
}

以上是关于花神的数论题的主要内容,如果未能解决你的问题,请参考以下文章

[数位dp] bzoj 3209 花神的数论题

BZOJ3209花神的数论题 数位DP

bzoj 3209: 花神的数论题 数位dp

[BZOJ3209]花神的数论题 组合数+快速幂

luogu_4317: 花神的数论题

bzoj3209 花神的数论题