zoukankan      html  css  js  c++  java
  • 【题解】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;
    }
    
  • 相关阅读:
    SQL SERVER的检查点checkpoint
    MySQL备份说明
    声明对象和创建对象的区别
    getParameter的用法总结
    Jsp的九大对象,七大动作,三大指令
    为什么内部类访问的外部变量需要使用final修饰
    java synchronized详解
    网上选课系统需求说明书
    第三次作业
    第二次作业
  • 原文地址:https://www.cnblogs.com/UntitledCpp/p/13921878.html
Copyright © 2011-2022 走看看