【洛谷P6476】涂色游戏

题目

题目链接:https://www.luogu.com.cn/problem/P6476

你有 \(10^{20}\) 个格子,它们从 \(0\) 开始编号,初始时所有格子都还未染色,现在你按如下规则对它们染色:

  1. 编号是 \(p_1\) 倍数的格子(包括 \(0\) 号格子,下同)染成红色。
  2. 编号是 \(p_2\) 倍数的格子染成蓝色。
  3. 编号既是 \(p_1\) 倍数又是 \(p_2\) 倍数的格子,你可以选择染成红色或者蓝色。

其中 \(p_1\)\(p_2\) 是给定的整数,若格子编号是 \(p_1\)\(p_2\) 的倍数则它必须要被染色。在忽略掉所有未染色格子后,你不希望存在 \(k\) 个连续的格子颜色相同,因为你认为这种染色方案是无聊的。现在给定 \(p_1\), \(p_2\), \(k\),你想知道是否有一种染色方案不是无聊的。

思路:

结论题。考场没有特判 \(k=1\)

首先 \(k=1\) 时,输出 No

容易发现只有相对小的数可能会被连续染上 \(k\) 个,所以如果一个数同时为 \(p_1,p_2\) 的倍数,那么肯定选择 \(p_2\) 更优。我们设 \(a\) 是较小数,\(b\) 是较大数。

我们设两个连续的 \(b\) 的倍数分别为 \(p,q(p<q)\)。为了我们就是要找是否存在一对 \(p,q\),使得 \((p,q)\) 中有 \(k\)\(a\) 的倍数。

那么我们其实只要找到距离上一个 \(b\) 的倍数最小的 \(a\) 的倍数,判断能否选择连续 \(k\)\(a\) 的倍数即可。说人话,就是对于所有的 \(ax\),取 \(ax\bmod b\) 最小的 \(x\) 来判断能否放连续 \(k\)\(a\) 即可。

根据裴蜀定理,\(ax\bmod b\) 除了 0 以外,最小只能为 \(\gcd(a,b)\)。而我们如果能确定在 \(10^{20}\) 内,对于每一组 \(a,b\) 必然存在一个 \(ax\leq 10^{20}\) 满足 \(ax\bmod b=\gcd(a,b)\),那么这道题就好办了。

因为 \(ax\bmod b\) 是有长度不超过 \(b\) 的循环节的,而 \(a,b\)\(\leq 10^9\),所以在不超过 \(10^{18}\) 时就一定会出现 \(ax\bmod b=\gcd(a,b)\) 的情况。

那么我们只需要判断 \(\gcd(a,b)+a(k-1)\) 是否严格小于 \(b\) 即可。

代码

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;

int a,b,k,d,T;

inline int read()
{
	int d=0; char ch=getchar();
	while (!isdigit(ch)) ch=getchar();
	while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
	return d;
}

int Gcd(int x,int y)
{
	if (!y) return x;
	return Gcd(y,x%y);
}

int main()
{
//	freopen("color.in","r",stdin);
//	freopen("color.out","w",stdout);
	T=read();
	while (T--)
	{
		a=read(); b=read(); k=read()-1;
		if (!k)  // 比赛没特判啊啊啊啊/kk
		{
			puts("No");
			continue;
		}
		if (a>b) swap(a,b);
		d=Gcd(b,a);
		if (1LL*a*k+d<b) puts("No");
			else puts("Yes");
	}
	return 0;
}
posted @ 2020-04-25 16:30  stoorz  阅读(...)  评论(...编辑  收藏