NYOJ 954

首先观察:

2! = 2×1                 = (2)10     = (10)2,          则第一个1是第2位,2!有1个质因数2
3! = 3×2×1             = (6)10     = (110)2,        则第一个1是第2位,3!有1个质因数2
4! = 4×3×2×1         = (24)10   = (11000)2,        则第一个1是第4位,4!有3个质因数2
5! = 5×4×3×2×1     = (120)10 = (1111000)2,     则第一个1是第4位,5!有3个质因数2
6! = 6×5×4×3×2×1 = (720)10 = (1011010000)2,则第一个1是第5位,  6!有4个质因数3

...

这时候规律就很明显了,就是有n个质因数2的话,就会在二进制形式下后面跟n个0,则所求答案就是n+1,即在n+1位上出现第一个1.  

这时候一个很朴素的思路是,测试n!的每个因子的质因数2的个数,然后加起来就好了。

代码如下:

 1 #include <iostream>
 2 using namespace std;
 3   
 4 int main(){
 5     long long n;
 6     while(cin>>n){
 7         long long res = 1;
 8         for(long long i=1;i<=n;i++){
 9             long long temp = i;
10             while(temp%2==0){
11                 res++; 
12                 temp/=2;
13             }
14         }
15         cout<<res<<endl;
16     }
17     
18     return 0; 
19 }
20         
View Code

此时复杂度为O(nlnn).  提交显示超时。

如何改进呢?

在二进制的形式下,每一位都有1/0两种填充方式,由于计算的是n!,所以这种“填充”是连续的,也就是说在*****0的基础上除以2(即右移一位)得到的就是该位的质因数2 的个数,只需要将这个过程一直做下去直到右移到位数为0即可。

代码如下:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 int main(){
 5     int n;
 6     long long ans;
 7     while(scanf("%d",&n)!=EOF){
 8         ans=0;
 9         while(n){
10             ans+=n>>1;  
11             n=n>>1; 
12         }
13         printf("%lld\n",ans+1);
14     }
15     return 0;
16 }
View Code

此时复杂度为O(lnn),可ac.

 

posted on 2017-01-05 17:53  逸阳  阅读(132)  评论(0编辑  收藏  举报

导航