sgu119



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;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值