题目链接:
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;
}