zoukankan      html  css  js  c++  java
  • P4317 花神的数论题

    题目背景
    众所周知,花神多年来凭借无边的神力狂虐各大 OJ、OI、CF、TC …… 当然也包括 CH 啦。

    题目描述
    话说花神这天又来讲课了。课后照例有超级难的神题啦…… 我等蒟蒻又遭殃了。 花神的题目是这样的:设 sum(i) 表示 i 的二进制表示中 1 的个数。给出一个正整数 N ,花神要问你 ∏Ni=1sum(i) ,也就是sum(1)~sum(N)的乘积。
    传送门

    输入输出格式
    输入格式:
    一个正整数 N。

    输出格式:
    一个数,答案模 10000007 的值。

    输入输出样例
    输入样例#1:

    3
    输出样例#1:

    2

    思路:
    一开始想的时候觉得不太对,因为自己想的思路非常简单,因为10^15表示成二进制数最多有50位,所以我们只要枚举这50位二进制中,含有1个1的数的个数,含有2个1的数的个数......即可,最后快速幂处理答案
    然后翻了翻题解发现思路好像就是这么简单?
    dp处理1的个数~~

    代码:

    #include<bits/stdc++.h>
    #define maxn 51
    #define ll long long
    
    using namespace std;
    ll f[maxn][maxn][maxn][maxn],n,p=1e7+7;
    ll x[maxn],ans[maxn];
    
    ll ksm(ll a,ll b)
    {
    	ll ans=1;
    	while(b)
    	{
    		if(b&1) ans=ans*a%p;
    		b>>=1;
    		a=a*a%p;
    	}
    	return ans;
    }
    
    ll _f(int cur,int up,int tmp,int d)
    {
    	if(cur==0) return tmp==d;
    	if(~f[cur][up][tmp][d]) return f[cur][up][tmp][d];
    	int lim=up?x[cur]:1;
    	ll ret=0;
    	for(int i=0;i<=lim;i++)
    		ret+=_f(cur-1,up&i==lim,tmp+(i==1),d);
    	return f[cur][up][tmp][d]=ret;
    }
    
    ll work()
    {
    	int cnt=0;
    	while(n)
    		x[++cnt]=n&1,n>>=1;
    	for(int i=1;i<=50;i++)
    		memset(f,-1,sizeof(f)),ans[i]=_f(cnt,1,0,i);
    	ll ret=1;
    	for(int i=1;i<=50;i++)
    	{
    		ret=ret*ksm(i,ans[i])%p;
    	}
    	return ret;
    }
    
    int main()
    {
    	scanf("%lld",&n);
    	printf("%lld",work());
    }
    
  • 相关阅读:
    .NET Core 服务调用 RPC
    从Docker 到 Kubernatetes 的跃迁之路
    同步异步-多线程梳理
    Net的微服务选型之路
    Visual Studio 2019安装SSIS
    HL7协议的基本语法
    vue学习笔记
    开发常用的部分sql语句总结
    VSPD虚拟串口来调试通信接口程序
    SSRS报表工具之合并行数据
  • 原文地址:https://www.cnblogs.com/yxr001002/p/14435949.html
Copyright © 2011-2022 走看看