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;
    }
    
  • 相关阅读:
    SAP S/4HANA extensibility扩展原理介绍
    SAP CRM系统订单模型的设计与实现
    使用nodejs代码在SAP C4C里创建Individual customer
    SAP Cloud for Customer Account和individual customer的区别
    Let the Balloon Rise map一个数组
    How Many Tables 简单并查集
    Heap Operations 优先队列
    Arpa’s obvious problem and Mehrdad’s terrible solution 思维
    Passing the Message 单调栈两次
    The Suspects 并查集
  • 原文地址:https://www.cnblogs.com/UntitledCpp/p/13921878.html
Copyright © 2011-2022 走看看