SGU119 Magic Pairs
题目大意:
“证明 对于任意一对 X ,Y 如果其满足条件 5X+4Y 能够被 23 整除 那么 3X+7Y 也一定能被23整除。”这个题目来自于俄罗斯萨拉托夫州数学奥林匹克竞赛(2001-2002)。
对于给出的一个整数N,和一对(A0,B0) 找到所有的整数对(A,B)满足 : 对于任意 X,Y 当 A0 * X + B0 * Y 能被 N 整除时 A * X + B * Y 也能被 N 整除
输入:
对于每个输入包含 N A0 和 B0 三个整数 (N ≤ 10000) 由空格隔开
输出:
第一行输出 (A,B) 总共的对数
接下来每一行输出一对(A,B) (A ,B ≤ 10000)
输出按照非降序输出
若A不相等则输出A小的那一个,如果相等则输出B小的那一个
样例输入:
3
1 2
样例输出:
3
0 0
1 2
2 1
乍一看很难的样子
10000*10000枚举保证超时。。。
思考一下,当A0*X+B0*Y可以被N整除时,(A0*k)%N*X+(B0*k)%N*Y也可以被N整除(很简单的定理)
所以我们只需要枚举k就可以了。
等下,怎么证明这样一定是所有解呢?
对于任意一组解A1,B1有:
A1=[A1+(N*m)]%N
即A1+(N*m)=(A0*K)
同理B1+(N*m')=(B0*K)
将一式乘X,二试乘Y,再相加可得:
A1*X+B1*Y+(N*m')*Y+(N*m)*X=(A0*K)*X+(B0*K)*Y
因为A1*X+B1*Y可以被N整除,(A0*K)*X+(B0*K)*Y也可以被N整除。
所以:(N*m')*Y+(N*m)*X也可以被N整除
因此:存在整数m',m使得:
A1+(N*m)=(A0*K)
B1+(N*m')=(B0*K)
(如果对证明有疑问可以参考另一种证明方法:SGU119 题解手记)
这里我要特别提到的是排序方法:
对于解对(X,Y),已知X,Y的范围,进行双关键字排序。
方法:基数排序法。
1.统计每个X,Y出现的次数。
2.对每个点对根据X,Y确定位置,给定一个顺序数组order[]
时间复杂度O(n)
优越吧!
注意事项的话上面的大神手记已经讲得很清楚了。
下面附上我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
struct answer
{
int x,y;
}ans[20001];
int total;
int g,n,a0,b0;
int numy[10001],numx[10001],ordery[20001],order[20001];
void sortx()
{
int i;
for (i=1;i<=total;i++)
ordery[++numy[ans[i].y-1]]=i;
for (i=1;i<=total;i++)
order[++numx[ans[ordery[i]].x-1]]=ordery[i];
return ;
}
void init()
{
int i;
scanf("%d%d%d",&n,&a0,&b0);
a0%=n;
b0%=n;
ans[++total].x=a0;
numx[ans[total].x]++;
ans[total].y=b0;
numy[ans[total].y]++;
for (i=2;;i++)
{
if ((a0*i)%n==ans[1].x && (b0*i)%n==ans[1].y)
break;
ans[++total].x=(a0*i)%n;
numx[ans[total].x]++;
ans[total].y=(b0*i)%n;
numy[ans[total].y]++;
}
for (i=0;i<=n;i++)
{
numx[i]+=numx[i-1];
numy[i]+=numy[i-1];
}
sortx();
printf("%d\n",total);
for (i=1;i<=total;i++)
printf("%d %d\n",ans[order[i]].x,ans[order[i]].y);
return ;
}
int main()
{
init();
return 0;
}