2020 CCPC Wannafly Winter Camp Day1 Div.1&2(H 最大公约数)(找规律+大整数乘法)

99封情书 提交于 2020-01-27 14:50:13

2020 CCPC Wannafly Winter Camp Day1 Div.1&2(H 最大公约数)(找规律+大整数乘法)

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

有三个人,A,B,C{A,B,C} ,其中 A{A}B{B} 共享了一个神秘的数字 k{k},已知 1kn1 \leq k \leq n
现在 A{A}C{C} 说:“k{k} 的值等于 x{x}”。
C{C} 不太信任 A{A},于是想向 B{B} 确认一下 k{k} 是否真的等于 x{x}B{B} 虽然不想直接把 k{k} 的值告诉 C{C},但是 B{B} 允许 C{C} 给出一个正整数 y{y}(注意 y{y} 可以大于 n{n}),然后 B{B} 会回答 gcd(k,y)\gcd(k,y)
现在给出 k,n{k,n},你需要帮助 C{C} 决定这样的 y{y} 的取值,使得 C{C} 一定可以通过 BB 的回答来判断 AA 有没有撒谎。如果这样的 yy 有多个,你需要输出最小的那个。

输入描述:

输入第一行是一个整数 T(1T50)T(1 \leq T \leq 50)
对于每组数据,输入一行两个整数 n,k(1kn500)n,k(1 \leq k \leq n \leq 500)

输出描述:

对于每组数据,输出一行一个整数,表示答案。如果满足条件的 yy 不存在,则输出 1-1

示例1

输入

3
10 1
10 4
10 7

输出

210
8
7

备注:

输入的 kk 指的是 AA 告诉 CC 的值,只需要检验它对不对就行

题解

题目中的 kk 是游戏开始前设定的未知数,而 xx 是游戏时 AA 给出的固定值,那么 kk 是变量。而备注中说

输入的 kk 指的是 AA 告诉 CC 的值,只需要检验它对不对就行

说明输入的是 nnxx

我们假设一个数字 ans=(n×x)ans = (所有小于等于n的素数的乘积 × x)

那么 gcd(x,ans)gcd(x,ans)gcd(k,ans)gcd(k,ans) 是否相等即代表 kkxx 是否相等。


证明:

  • 如果 kk 不是 xx 的倍数那么 gcd(k,ans)gcd(k,ans) 一定不能整除 xx(即 x%gcd(k,ans)0x\%gcd(k,ans)≠0 ),而 ansansxx 的倍数,所以 gcd(x,ans)=xgcd(x,ans)=x ,其一定能整除 xx (即 x%gcd(x,ans)=0x\%gcd(x,ans)=0 ),所以 gcd(k,ans)gcd(x,ans)gcd(k,ans)≠gcd(x,ans)
  • 如果 kkxx 的倍数且 kk 不等于 xx ,且 ans=(n×x)ans = (所有小于等于n的素数的乘积 × x) ,那么 gcd(k,ans)=z×x(z1)gcd(k,ans)=z×x(z是大于1的整数)gcd(x,ans)=xgcd(x,ans)=x 所以 gcd(k,ans)gcd(x,ans)gcd(k,ans)≠gcd(x,ans)
  • 如果 kk 等于 xx ,则 gcd(k,ans)=gcd(x,ans)gcd(k,ans)=gcd(x,ans)

证毕。


综上所述,这道题的答案就是 ansans

ans=(n×x)ans = (所有小于等于n的素数的乘积 × x)

注意题目要用大整数乘法。

代码

#include<bits/stdc++.h>
using namespace std;

int p[505], n, m, i, j, t, k, l, a[505];
bool vis[505];

void mul(int x) {
	int i; // 定义临时变量 !
	for (i = 0; i < l; i++) a[i] *= x;
	for (i = 0; i < l; i++) {
		a[i + 1] += a[i] / 10;
		a[i] %= 10;
	}
	for (; a[l]; l++) {
		a[l + 1] = a[l] / 10;
		a[l] %= 10;
	}
}

int main() {
	freopen("in.txt", "r", stdin);
	n = 500;
	for (i = 2; i <= n; i++) {	//线筛
		if (!vis[i]) p[m++] = i;
		for (j = 0; j < m && i*p[j] <= n; j++) {
			vis[i*p[j]] = 1;
			if (i%p[j] == 0) break;
		}
	}
	scanf("%d", &t);
	while (t--) {
		scanf("%d%d", &n, &k);
		memset(a, 0, sizeof(a));
		a[0] = l = 1;
		for (i = 0; i < m && k*p[i] <= n; i++) mul(p[i]);
		mul(k);
		for (i = l - 1; ~i; i--) printf("%d", a[i]);
		puts("");
	}
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!