• 【题解】P4317 花神的数论题,关于luogu题解粉兔做法的理解


    link

    题意

    ( ext{sum}(i)) 表示 (i) 的二进制表示中 (1) 的个数。给出一个正整数 (N) ,求 (prod_{i=1}^{N} ext{sum}(i))

    思路

    换一种角度看这个乘积,会发现就相当于统计出 (1sim N) 中 1 的个数为 (k) 的数量 (cnt_k) ,然后 (prod k^{cnt_k}) 即可。

    (怎么那么水啊,这都什么垃圾紫题,题白挑了)为了让这道题更有价值,代码实现非常的神仙。Orz粉兔。

    粉兔的代码看了很久才理解……luogu上至今没有看到公开的详解。

    这里注释的是我认为正确的理解,若有差错还请指正。

    代码

    #include <cstdio>
    #define ll long long
    const ll mod=1e7+7;
    ll n,ans=1,cnt,f[50];
    
    ll power( ll a,ll b )
    {
    	ll res=1;
    	for ( ; b; b>>=1,a=a*a%mod )
    		if ( b&1 ) res=res*a%mod;
    	return res;
    }
    
    int main()
    {
    	scanf( "%lld",&n );
    
    	cnt=0; f[0]=0;
    	for ( int len=49; ~len; --len )
    	{
    		for ( int i=49; i; --i )			
    			f[i]+=f[i-1];
    		if ( n>>len&1 ) f[cnt]++,cnt++;			
            //cnt记录的是除了现在这一位,之前有的1的个数,f[cnt]++表示,这一位的1产生了一种使得前面的1全部能取到的方案。
    	}
    	f[cnt]++;		//加上本身
    //之前一直想不明白,如果这样枚举,为什么能直接从49开始。
    //一开始的想法是预支最高位的1,这样当前每次加一位就能取1,对应 f[i-1] 到 f[i] 的转移
    //但是这样有个问题,就是最高位没有1了怎么办,这样预支无效,答案就会偏大
    //后来发现,关键在外层循环。当位数大于二进制下n的位数的时候,f始终为0,最后一句if 不会执行,也就不会出现上述问题。
    //一旦开始累加出现了值,那么一定就是有高位可以预支了。否则 if 中的等号不会成立。
    	for ( int i=1; i<=49; ++i )
    		ans=ans*power( i,f[i] )%mod;
    	
    	printf( "%lld",ans );
    	return 0;
    }
    
  • 相关阅读:
    一二线城市知名 IT 互联网公司名单!
    分布式理论- CAP定理
    Linux中安装ActiveMQ完整教程
    Nginx安装-配置负载均衡
    基于SpringBoot+Vue在线学习系统实现
    序列化多个对象和反序列化遍历一个文件中的所有对象原理讲解
    从源码看懂HashMap
    Mac在已有jdk1.8的环境下安装jdk1.6
    mac通过Parallels Desktop虚拟机实现共享windows独有软件提供的特殊网络
    算法题汇总
  • 原文地址:https://www.cnblogs.com/UntitledCpp/p/13921878.html
Copyright © 2020-2023  润新知