gcdDepth

题目链接:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1054。

题目大意 :在(y0,y1)的范围内找出有多少个数满足gcd(x,y)的深度(递归调用的次数)等于d。

解题思路:这题刚那拿到第一反应是拉梅定理,找了好久没找到合适的计算方法,经同学提醒发现随便确定一个x,在模拟一下这个过程就能找到规律,当y大于x后gcd(x,y)的深度就会出现周期性变化,这样就可以对10的9次方的范围计数了,由于x=y时比较特殊,最后特判一下,所以这题就变成了一个模拟,看来自己写代码的能力还有待提高,wrong的7发后才过委屈。但还是把丑的一比的代码贴在这,仅供参考。

 

/* ********************************
Author			: danmu
Created Time	: 2016年04月17日 星期日 03时24分12秒
File Name		: gcdDepth.cpp

Vim Command
copy -> yy
paste -> p P
del this line -> dd
Ctrl-Z -> u U
copy into system -> "+y
******************************** */

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <string>
#include <vector>
#include <cstdio>
#include <stack>
#include <queue>
#include <cmath>
#include <list>
#include <map>
#include <set>

#define ULL unsigned long long
#define PI 3.1415926535
#define INF 0x3f3f3f3f
#define LL long long
#define eps 1e-8

using namespace std;
int num1[200010],num2[200010];
int gcdDepth(int x,int y){
	if(y==0)
		return 0;
	return gcdDepth(y,x%y)+1;
}
int main()
{
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
	int x,d,y0,y1;	
	while(scanf("%d%d%d%d",&x,&d,&y0,&y1)!=EOF){
		int ans=0;
		if(x==0){
			if(d==0){
				if(y0==0)
					ans=1;
			}
			else if(d==1){
				if(y0==0)
					ans=y1;
				else
					ans=y1-y0+1;
			}
		}
		else{
			int flag=0,tmp;
			if(d==0){
				if(y0==0)
					ans=1;
				flag=1;
			}
			for(int i=0;i<x&&!flag;++i){
				tmp=gcdDepth(x,i);
				if(tmp==d)
					num1[i+1]=num1[i]+1;
				else
					num1[i+1]=num1[i];
				if(tmp+2==d)
					num2[i+1]=num2[i]+1;
				else
					num2[i+1]=num2[i];
			}
			tmp=y0;
			if(!flag&&tmp<x){
				if(y1<x){
					ans+=num1[y1+1]-num1[tmp];
					flag=1;
				}
				else{
					ans+=num1[x]-num1[tmp];
					tmp=x;
				}
			}
			if(!flag&&tmp%x){
				if(y1<(tmp/x+1)*x){
					ans+=num2[y1%x+1]-num2[tmp%x];
					flag=1;
				}
				else{
					ans+=num2[x]-num2[tmp%x];
					tmp+=x-tmp%x;
				}
			}
			//printf("%d\n",tmp);
			if(!flag)
				ans+=(y1/x-tmp/x)*num2[x];
			//printf("%d %d\n",tmp,(y1/x-tmp/x)*num2[x]);
			if(!flag)
				ans+=num2[y1%x+1];
			//printf("%d\n",ans);
			if(y0<=x&&y1>=x){ 
				if(d==1)
					++ans;
				else if(d==2)
					--ans;
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值