HDU4596 Yet another end of the world(数学公式推演+数论定理--2013南京邀请赛)

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4596

 

题目描述:

1)给N组数,每组X,Y,Z三个数

2)是否存在一个数ID使得同时满足:Yi<=ID%Xi<=Zi 和 Yj<=ID%Xj<=Zj

3)  Y<=Z<X<2*10^9

 

解题思路:

数学题尽量用公式表示,利用公式推演出熟悉的式子,利用现成的已知的定理去解决,

即使不知道这个定理怎么去证明,自己解不出的题,就交给N多年前的前辈门吧,直接

使用他们的定理就行了,有兴趣的话可以以后慢慢证。

y1<= id%x1 <=z1
y2<= id%x2 <=z2

设id/x1=a1,id/x2=a2
    id%x1=b1,id%x2=b2
 
  则有:

  id=a1x1+b1
  id=a2x2+b2
  a1x1+b1=a2x2+b2
  

=>a1x1-a2x2=b2-b1

   线性不定方程组
   有整数解的条件???

   数论定理:线性方程组有整数解的条件是b2-b1是gcd(x1,x2)的整数倍数

   另外我们来研究一下同一个数对不同数同时取余的规律:

   可以发现:

   1)同一个数对不同数a,b同时取余结果的周期是a,b的最小公倍数;

   2)同一个数对不同数a,b同时取余结果的所有差值间隔为最大公约数,

         即设a,b的最大公约数为x,则他们的所有差值只可能为:0,x,2x,3x,...,nx...

         并且覆盖一定范围内所有的连续的x的倍数;


  基于以上定理及规律,此题解法如下:

  只需要判断一下两个区间[yi,zi]和[yj,zj]的差值区间[yj-zi,zj-yi]是否可能存在gcd(xi,xj)的倍数

  

程序代码:

一部分参考了别人的:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 100001
#define Max(a,b) (a)>(b)?(a):(b)
#define Min(a,b) (a)<(b)?(a):(b)

struct Node
{
	int x,y,z;
}node[1005];

int gcd(int a,int b)
{
	if(b==0) return a;
	else return gcd(b,a%b);
}
int check2(int d,int l,int r)
{
	if(l%d==0 || r%d==0) return 1;
	else if(r/d>l/d) return 1;
	else return 0;
}
int check(int i,int j)
{
	if(node[i].y>node[j].z || node[j].y>node[i].z)
	{
		if(node[i].y>node[i].z) swap(i,j);
		int d=gcd(node[i].x,node[j].x);
		if(check2(d,node[j].y-node[i].z,node[j].z-node[i].y))
		    return 1;
		else
		    return 0;
	}
	return 1;
}

int main(){
	//freopen("iofile\\input.txt","r",stdin);
	int n,i,j;
	while(~scanf("%d",&n))
	{
		for(i=1;i<=n;i++)
			scanf("%d %d %d",&node[i].x,&node[i].y,&node[i].z);
		
		int flag=0;
		for(i=1;i<=n;i++)
		{
			for(j=i+1;j<=n;j++)
			{
				if(check(i,j)) {flag=1;break;}	
			}
			if(flag) break;
		}
		
		if(!flag)printf("Can Take off\n");
        else printf("Cannot Take off\n");
	}
	return 0;
}




   

 

posted on 2013-08-18 08:43  Gddxz  阅读(199)  评论(0编辑  收藏  举报

导航