中北校赛练习里的一道题,比较难写 htu1602

00003:GCD depth

总时间限制:
5000ms
内存限制:
65536kB
描述
In mathematics, the greatest common divisor (gcd), also known as the greatest common factor (gcf), or highest common factor (hcf), of two or more non-zero integers, is the largest positive integer that divides the numbers without a remainder. For example, the GCD of 8 and 12 is 4.
------ From Wikipedia

In this problem,we will introduce a new value related to GCD,which is GCD depth. To GCD depth,follow function will discribe it clearly.

int GCD_depth( int x , int y ) {
if ( y == 0 ) return 0;
else return GCD_depth( y , x%y ) + 1;
}

And we define the GCD depth of y with x is GCD_depth(x,y).For example , GCD depth of 5 with 3 is 4.You can find the GCD depth of two numbers easily ,but LH wants know that: for a number x, how many numbers meet the condition that the GCD depth with x equals to d in the interval [y0,y1]? So please help LH to find the answer quickly.
输入
There are several test cases, each test case contains four Non-negative integers x( 0 <= x <= 200000) , d( 0 <= d <= 30 ),y0 ,y1(0 <= y0 <= y1 <= 10^9),which descripted as above.
The input will finish with the end of file.
输出
For each the case, just output a integer which represent the number of integers meeted the discripted condition.
样例输入
7 2 0 5
3 0 0 1
11 1 2 8
样例输出
2
1
0
 
  
四个数 N, M, S, E, 求 GCD_depth( N, i ) == M 的个数,其中 i 属于 [s, e]。

  思路:该题我们只要将 i 属于 [0 - N) 的GCD_depth计算出来,然后大于N的数就用 GCD_depth( N, i% N ) + 2 == M 去统计了,自己推一下就能明白为什么了。 注意当这个数等于N的时候比较特殊,这时候是加1而不是加 2。 主要是区间的读取边界太难处理了,代码比较丑。

 
  
 
  
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
using namespace std;
int gcd( int a, int b )
{
    if( b== 0 )
    {
        return 0;
    }
    else return gcd( b, a% b )+ 1;
}

int rec[200005];//储存每一个的深度

int main()
{
    int N, M, s, e;
    while( scanf( "%d %d %d %d", &N, &M, &s, &e )!= EOF )
    {
        int base= 0, cnt= 0, beg, end;
        //处理边界
        if( N== 0 )
        {
            if( M== 1 )
            {
                int k= 1;
                if( s== 0 )
                {
                    k= 0;
                }
                cnt= e- s+ k;
            }
            else if( M== 0 )
            {
                int k= 0;
                if( s== 0 )
                {
                    k= 1;
                }
                cnt= k;
            }
            printf( "%d\n", cnt );
            continue;
        }
        //处理边界
        for( int i= 0; i< N; i++ )
        {
            rec[i]= gcd( N, i );
            if( rec[i]+ 2== M )
            {
                base++;
            }
        }
        if( s>= N )
        {
            beg= ( int )ceil( 1.0* s/ N );
            end= ( int )floor( 1.0* e/ N );
            for( int i= s; i< beg* N; ++i )
            {
                if( rec[i% N]+ 2== M )
                {
                    cnt++;
                }
            }
            for( int i= end* N; i<= e; ++i )
            {
                if( i!= N )
                {
                    if( rec[i% N]+ 2== M )
                    {
                        cnt++;
                    }
                }
            }
            cnt+= base* ( end- beg );
            if( s== N )
            {
                if( rec[0]+ 1== M )
                {
                    cnt++;
                }
                else if( rec[0]+ 2== M )
                {
                    cnt--;
                }
            }
        }
        else if( e>= N )
        {
            end= ( int )floor( 1.0* e/ N );
            for( int i= s; i< N; ++i )
            {
                if( rec[i]== M )
                {
                    cnt++;
                }
            }
            for( int i= end* N; i<= e; ++i )
            {
                if( i!= N )
                {
                    if( rec[i% N]+ 2== M )
                    {
                        cnt++;
                    }
                }
            }
            cnt+= base* ( end- 1 );
            if( rec[0]+ 1== M )
            {
                cnt++;
            }
            else if( rec[0]+ 2== M )
            {
                cnt--;
            }
        }
        else
        {
            for( int i= s; i<= e; ++i )
            {
                if( rec[i]== M )
                {
                    cnt++;
                }
            }
        }
        printf( "%d\n", cnt );
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值