第10-3关 报数游戏(大数据)

发布时间: 2017年5月14日 16:04   最后更新: 2017年5月14日 16:06   时间限制: 1000ms   内存限制: 128M

描述

伊苏比前往北极村支教,北极村共有N只北极熊。于是伊苏比让这些北极熊玩报数游戏。N只北极熊站成一排,从左至右从1开始依次往上报数。玩完一轮后,伊苏比发现这个游戏太简单了。于是她选了3个不同的数x,y,z;从1依次往上开始报数,遇到x的倍数、y的倍数或z的倍数就跳过。如果x=2,y=3,z=5;第一只报1,第2只得跳过2、3、4、5、6,报7;第3只得跳过8、9、10,报11.请你来计算,第N只北极熊报的数字是多少?

输入

四个整数x,y,z,N.

输出

第N只北极熊所报的数字。

样例输入1  复制
2 3 5 2
样例输出1
7
样例输入2  复制
6 2 4 10000
样例输出2
19999
提示

数据范围:2≤x,y,z≤10^7,1≤N≤10^17

标签

伊苏比系列

来源
伊苏比的梦幻之旅(三)
选择语言

 C (GCC 4.8)  C++ (G++ 4.3)  Java (Oracle JDK 1.7)


我们可以通过容斥定理计算出1-q之间有多少个数会被报到(不是x,y,z任何一个数的倍数),直接计算不是其倍数的数不好计算。可以计算出是x,y,z中一个数的倍数的数的个数。计算公式为S=q/x+q/y+q/z-q/gcd(x,y)-q/gcd(y,z)-q/gcd(z,x)+q/gcd(x,y,z);q-S就是报到的数。然后我们可以通过二分的方式找出最早报出N个数的q值,就是本题的答案。注意x,y,z均为10^7,直接乘会爆long long,就得用相除的方式判断一下gcd(x,y,z)是否比10^18大,如果比他大的话就不用管它了。

题解:javascript:void(0)

#include <stdio.h>
#include <string.h>
#include<functional>
#include <queue>
#include <vector>
#include <math.h>
#include <algorithm>
using namespace std;
typedef long long ll;
#define maxn 1000005
ll gcd(ll x,ll y)
{
	if(y==0)
		return x;
	return gcd(y,x%y);
}
ll lcm(ll a,ll b)
{
	ll res,t;
	res=a/gcd(a,b);
	t=1000000000000000000/res;
	if(t<b)//如果超线,不管他就好了
		return -1;
	res*=b;
	return res;
}
int main(void)
{
	ll x,y,z,b,i,l,r,m,xy,yz,xz,xyz,n;
	scanf("%lld%lld%lld%lld",&x,&y,&z,&n);
	l=0;r=1000000000000000000;         
	while(l+1<r)
	{
		ll ans=0;
		m=(l+r)/2;
		ans+=(m/x+m/y+m/z);
		xy=lcm(x,y);
		yz=lcm(y,z);
		xz=lcm(x,z);
		xyz=lcm(xy,z);
		ans-=(m/xy+m/xz+m/yz);
		if(xyz!=-1)
			ans+=m/xyz;
		/*if(m-ans==n)
		{
			printf("%lld\n",m);
			return 0;
		}*/
		if(m-ans>=n)
			r=m;
		else
			l=m;
	}
	printf("%lld\n",r);
	return 0;
}