P4317 花神的数论题

在这里插入图片描述
着重考虑下 s u m ( i ) sum(i) sum(i)这个东西,二进制数表示情况下1的数量,如果限定的是位数而不是 N N N的话可以去考虑搞一下组合数学.
s u m ( i ) sum(i) sum(i)的数量太多了,考虑下分组来计算
f ( i ) : 有 f ( i ) 个数字 , 对应的 s u m 值是 i f(i):有f(i)个数字,对应的sum值是i f(i):f(i)个数字,对应的sum值是i
a n s = ∏ i f ( i ) ans=\prod i^{f(i)} ans=if(i)
然而想了半天似乎并不会求这个东西,学了一天数位dp后回来写这个题
我去,和我想象的又不太一样,第一题写的是十进制意义下的一个题目,这个题是二进制的
学成归来,运用下数位dp的思路考虑下这个问题.
快有好几天没写,回顾下要做的东西:
需要求解一个函数 f ( i ) : i 个 1 出现的次数 f(i):i个1出现的次数 f(i):i1出现的次数
状态设置为 d p ( c u r , n u m , t o p ) dp(cur,num,top) dp(cur,num,top),在选第 c u r cur cur个数字,已经选了 n u m num num个1,是否贴着上界 t o p top top
然而这个题最大的坑点是:你 d f s dfs dfs算出来的是一个指数,指数是不能取模的,就像快速幂里面 p w ( a , b ) pw(a,b) pw(a,b)
取模是只能对底数取模 , 因为 a b % m o d ! = a b % m o d 取模是只能对底数取模,因为a^{b\%mod}!=a^b\%mod 取模是只能对底数取模,因为ab%mod!=ab%mod
然后 d f s dfs dfs过程不要取模就可以了

/*
I don't wanna be left behind,Distance was a friend of mine.
Catching breath in a web of lies,I've spent most of my life.
Catching my breath letting it go turning my cheek for the sake of this show
Now that you know this is my life I won't be told what's supposed to be right
Catch my breath no one can hold me back I ain't got time for that.
*/
#include<bits/stdc++.h>
using namespace std;
const int maxn = 50+5;
const int INF = 1e9+7;
typedef long long ll;
typedef pair<int,int> pii;
#define all(a) (a).begin(), (a).end()
#define pb(a) push_back(a)
ll dp[maxn][maxn][2];
int a[maxn];ll f[maxn];
ll mod = 1e7+7;
ll dfs(int cur,int num,bool top,int limit){
	if(cur==0){
		if(num==limit) return 1;
		return 0;
	}
	ll &ans = dp[cur][num][top];
	if(ans!=-1) return ans;
	ans = 0;
	int bound = top?a[cur]:1;
	for(int i=0;i<=bound;i++){
//		if(i==1&&num==limit) continue;
		ans+=dfs(cur-1,num+i,top&&(i==bound),limit); 
	}
	return ans;
}
void solve(ll n){
	int len = 0;
	while(n) a[++len] = n&1,n>>=1;
	for(int i=1;i<=50;i++){
		memset(dp,-1,sizeof(dp));
		f[i] = dfs(len,0,1,i);
	}
}
ll pw(ll a,ll b){
	ll ans=1;
	while(b){
		if(b&1) ans = ans*a%mod;
		b>>=1;a = a*a%mod;
	}
	return ans%mod;
}
int main(){
    ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	ll n;cin>>n;
	solve(n);
	ll ans = 1;
	for(int i=1;i<=50;i++){
		ans = ans * pw(i,f[i])%mod;
	}
	cout<<ans<<"\n";
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

minato_yukina

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值