zoukankan      html  css  js  c++  java
  • KeepCode 4 解题报告

      解题报告转摘录自: jian1573

      原文链接:http://www.cnblogs.com/jian1573/archive/2013/01/11/2857010.html

     

    IDOriginTitle
    Problem A HDU 1787 A
    Problem B HDU 1695 B
    Problem C HDU 4279 C
    Problem D HDU 1395 D
    Problem E HDU 1262 E
    Problem F HDU 1576 F

    Problem A

       红果果的欧拉函数;

    View Code
    View Code 
     #include <iostream>   
     using namespace std;  
     //  x=p1^e1*p2^e2~~~pn^en 
     //phi(x)=(p1-1)*p1^(e1-1)*(p2-1)*p2^(e2-1)~~~(pn-1)*pn^(en-1)
     int phi(int m)  
     {  
         int i,s=1;  
         for(i=2;i*i<=m;i++)  {  
             if(m%i==0){  
                 m/=i;  
                 s*=i-1;  
                 while(m%i==0) {  
                     m/=i;  
                     s*=i;  
                 }  
             }  
         }  
         if(m>1)  
             s*=m-1;  
         return s;  
     }  
     int main()  
     {  
         int m;  
         while(cin>>m && m)
             cout<<m-1-phi(m)<<endl;  
         return 0;  
     }

    Problem B

      

      题意: 在1~a, 1~b中挑出(x,y)满足gcd(x,y) = k , 求(x,y) 的对数 , a,b<=10^5

      思路: gcd(x, y) == k 说明x,y都能被k整除. 问题就可以转化为了求1~a/k 和 1~b/k间互质对数的问题;

      我们让b>=a; 然后在[1....b/k]进行枚举,对于每一个i,我们只要在1...min(i-1,a)中找到与i互质数,记录个数,然后累加就得到结果了;

      当i<=a/k时,我们可以直接用欧拉函数计算出与i互质的个数;

      当i>a/k时,先将i质因数分解,求得[1,2,...,b/k] 里所有能被x的质因数整除的数的个数,即不互质的数的个数,然后用b/k减去即可;

       而 我们枚举i的质因数利用容斥原理, 容斥原理的具体如下:

      区间中与i不互质的个数 = (区间中i的每个质因数的倍数个数)-(区间中i的每两个质因数乘积的倍数)+(区间中i的每3个质因数的成绩的倍数个数)-(区间中i的每4个质因数的乘积)+...

    参考代码

    View Code
    View Code 
     #include<iostream>
     #include <cstdio>
     using namespace std;
     const int Max=100005;
     __int64 elur[Max];//存放每个数的欧拉函数值
     int num[Max];//存放数的素因子个数
     int p[Max][20];//存放数的素因子
     void init()//筛选法得到数的素因子及每个数的欧拉函数值
     {
         elur[1]=1;
         for(int i=2;i<Max;i++)
         {
             if(!elur[i])
             {
                 for(int j=i;j<Max;j+=i)
                 {
                     if(!elur[j])
                         elur[j]=j;
                     elur[j]=elur[j]*(i-1)/i;
                     p[j][num[j]++]=i;
                 }
             }
             elur[i]+=elur[i-1]; //进行累加(法里数列长度)
         }
     }
     int dfs(int idx,int b,int now)//求不大于b的数中,与now不互质的数的个数;
     {                                //dfs()写的容斥原理
         int ans=0;
         for(int i=idx;i<num[now];i++)//容斥原理来求A1并A2并A3.....并Ak的元素的数的个数.
             ans += b/p[now][i]-dfs(i+1,b/p[now][i],now);
         return ans;
     }
     
     int main()
     {
         int t,a,b,c,d,k;
         init();
         scanf("%d",&t);
         for(int ca=1;ca<=t;ca++)
         {
             scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
             printf("Case %d: ",ca);
             if(k==0)
             {
                 printf("0\n");
                 continue;
             }
             if(b>d)
                 swap(b,d);
             b/=k;  d/=k;
             __int64 ans=elur[b];
             for(int i=b+1;i<=d;i++)
                 ans+=b-dfs(0,b,i);//求不大于b的数中,与i不互质的数的个数
             printf("%I64d\n",ans);
         }
         return 0;
     }

    Problem C

      题意  

      :给定一个数N, 在[1,N)中的数M, gcd( M, N ) != 1, 且N%M !=  0; 那么M就为N的一个special number, f( x ) 为统计 x 的special number的个数, 如果f( x )为奇数,那么x就为一个 real numbers. 求给定区间的real number数.

      思路:

      先看f(x),由题意得f(x)=x-phi( x ) - g(x)+1;(  phi(x)为欧拉函数, g(x)为因子个数, +1 是因为1在phi(x)和g(x)中都算了 );

      而real number只与f(x)的机偶性有关所以我们只讨论phi(x)和g(x)的奇偶性;

      我们知道当x>2时phi(x)为偶数;

      g(x)约数个数,我们由基本定理可得,x=p1^e1*p2^e2*…pn^en,而由计数方法易知 x的约数个数为 g(x)=(e1+1)*(e2+1)*…(en+1)的;

      所以若要使 g(x) 为奇数,充要条件是(ei+1)都为奇数,即质数的幂都为偶数。所以此时 x必然是一个平方数;

      综上,x为平方数,其约数个数为奇数;x为非平方数,其约数个数为偶数;

      所以,当x>2时, 若x为平方数,f(x)=x-奇-偶+1,要使f(x)为奇数,则x必为奇数;若x为非平方数,f(x)=x-偶-偶+1,

      要使f(x)为奇数,则x必为偶数。 当x=1或2时,f(x)=0.

      综上,real numbers F(x) 的值为[3,x]中,奇数平方数+偶数非平方数的个数和,即 偶数个数-偶数^2的个数+奇数^2的个数。

      而偶数个数为 x/2-1,-1是为了把2减掉。偶数^2个数为 sqrt(x)/2,奇数^2个数为 ( sqrt(x)-(sqrt(x)/2) )-1,

      这里-1是为了把1减掉。所以,化简后,F(x) = x/2-1+(sqrt(x)%2? 0: -1).

    解题代码

    View Code
    View Code 
     #include<stdio.h>
     #include<string.h>
     #include<stdlib.h>
     #include<math.h>
     
     __int64 get(__int64 x)
     {
         if(x<=2) return 0;
         return x/2-1+( (__int64)sqrt(1.0*x) %2? 0: -1);        
     }
     
     int main()
     {
         int T;
         scanf( "%d", &T );
         while(T--)
         {
             __int64 a, b;
             scanf("%I64d%I64d", &a, &b);
             printf("%I64d\n", get(b)-get(a-1));
         }
     }

    Problem D

      

      思路: 由题意得N=2^x(x>=1)为偶数, 所以当 n 也为偶数时  N%n必为偶数, 故不存在;

      当n为奇数时,利用同余定理求;

    参考代码

    View Code
    View Code 
     #include <iostream>
     #include <cstdio>
     #include <string>
     #include <cstring>
     #include <cmath>
     using namespace std;
     
     int main( )
     {
         int N;
         while( scanf( "%d", &N )!= EOF ){
             if( N==1 || !(N&1) )
                 printf( "2^? mod %d = 1\n", N );
             else{
                 int t=2, ans=1;
                 while( t != 1 ){
                     t <<= 1;
                     t%=N;
                     ans++;
                 } 
                 printf( "2^%d mod %d = 1\n",ans, N );
                 
             }
         }
         return 0;
     }

    Problem E

    View Code
    View Code 
     #include <stdio.h>
     #include <stdlib.h>
     #include <math.h>
     int a[10005]={0};
     void fun(  )
     {
         a[1]=a[0]=1;
         for( int i=4; i<10005; i+=2 )
             a[i]=1;
         for( int i=3; i <= ( int )sqrt( 10005 ); i+=2 )
         {
             if(a[i]==0)
                 for( int j=i*i; j<10005; j += ( i+i ) )    
                 {
                     a[j]=1;    
                 }
         }      
     }
     
     int main()
     {
         fun( );
         int n;
         while( scanf( "%d", &n ) != EOF )
         {
             for( int i=n/2; i>1; i-- )
             {
                 if( a[i]==0 && a[n-i]==0 )
                 {
                         printf( "%d %d\n", i, n-i );
                     break;    
                 }        
             }    
         }
         return 0;
     }

    Problem F

      

      思路:由题意可知,一定有解,而且解空间很小, 故可以枚举;

      M=9983, n=A%M gcd( b,M )==1, ans=(A?B)%M,

      则 n == (ans*b)%M;

      因为: A%M == (A/B*B)%M==(A/B%M * B%M)%M== (ans*B%M)%M;

    参考代码

    View Code
    View Code 
     #include <iostream> 
     #include <cstdio> 
     #include <string.h> 
     using namespace std; 
      
     int main(){ 
         int T; 
         scanf("%d",&T); 
         while(T--){ 
           __int64 n,b; 
           int x; 
           scanf("%I64d%I64d",&n,&b); 
           for(int i = 0;i < 9973; ++i){ 
               if(( b * i - n ) % 9973 == 0){ 
                 x = i; 
                 break; 
               } 
           } 
           printf("%d\n",x);  
         } 
         return 0; 
     }
  • 相关阅读:
    VNC跨平台远程桌面的安装与使用
    Apache 的编译安装
    Xming配置
    工作杂记
    自动创建系统用户脚本
    关于linux网络基础记录
    Linux的setup命令启动服务名称和功能
    涉密计算机检查工具
    Nginx压力测试工具之WebBench
    关于系统性能检测的一些使用
  • 原文地址:https://www.cnblogs.com/yefeng1627/p/2857026.html
Copyright © 2011-2022 走看看