题解【NOI Online #2 提高组】涂色游戏

题目链接

题意简述

有两个数aba\le b,给出kk,问是否存在mb<na<(n+1)a<(n+k1)<(m+1)b,(m+1)b<1020,m,nN,n1mb<na<(n+1)a<\cdots (n+k-1)<(m+1)b,(m+1)b<10^{20},m,n\in N,n\ge 1。存在输出“NO”,不存在输出“YES”(由于转换了求的东西所以存在和不存在与原题输出相反)。

题解

先说一下为什么这么化简题意。原题中的p1,p2p_1,p_2这里用a,ba,b表示。不妨设aba\le b,则染色的情况必定为aabaabaa\cdots aba\cdots aba\cdots的情形。可以发现,相当于是bb在截断aa的连续染色。而为了实现原题中不超过k个连续的愿望lcm(a,b)lcm(a,b)显然要染成bb去防止aa的延伸。接下来只需要看是否在1020110^{20}-1的范围内,每个bb之间间隔的aa的数量都小于k。当然,首先要特判k=1k=1的情况。

接下来讲一下我的解题思路。一开始是想至少搞一个下界出来,即:假设每个bb之间夹的aa的数量最多为cc,则cb1ac\ge \lfloor\frac{b-1}{a}\rfloor,也就是一开始0b0\thicksim b中存在的aa的数量。仔细想想,由于b1=b1a+r,0r<ab-1=\lfloor\frac{b-1}{a}\rfloor+r,0\le r < a,如果想在两个bb地倍数之间的a开头往前或结尾往后扎扎实实地再塞进一个aa是不可能的,想要再添加只有可能是存在一个数λ,mb<λ<mb+r\lambda,mb<\lambda< mb+r。这样好像讲的有点乱,看图明白一点:
1
2

截取线段和什么类似?取模!若λ\lambda存在,则不可避免的最多颜色连续数b1a+1\lfloor\frac{b-1}{a}\rfloor+1,不然,则为b1a\lfloor\frac{b-1}{a}\rfloor。即为判定axt(mod b)(0t<r)ax\equiv t(mod\ b)(0\le t<r)是否有解。进一步的,判定ax+by=tax+by=t是否有解。又由裴蜀定理知,该方程有解的充要条件为gcd(a,b)t\gcd(a, b)|t。且rr可以取遍0r10\thicksim r-1的整数,所以只需判断rrgcd(a,b)\gcd(a, b)的大小关系。如此一来,只需将最多颜色连续数kk进行比较,若kk比较大则有解,否则无解。本题就得到了解决。特殊地,当aba|br=0r=0,此时是可以不让bb染成aa的,代入发现同样可以通过比较rrgcd(a,b)\gcd(a,b)的大小关系获得正确答案。

等等,我们还有个范围问题!怎么确定如此找到的(m+1)b(m+1)b是否小于102010^{20}呢?设d=gcd(a,b)d=\gcd(a,b),由于ax+by=tax+by=t的解集与adx+bdy=td\frac{a}{d}x+\frac{b}{d}y=\frac{t}{d}相同,不妨先设aba\bot b
先证明一个引理:当aba\bot b时,{0,a,2a,,(b1)a}\{0,a,2a,\cdots,(b-1)a\}构成bb的完全剩余系。
首先,{0,a,2a,,(b1)a}\{0,a,2a,\cdots,(b-1)a\}{0,1,2,,b1}\{0,1,2,\cdots,b-1\}在元素个数上相同。下用反证法证明原集合中元素对bb取模结果两两不同即可。
axay(mod b)(0x,y<p,xy)ax\equiv ay(mod\ b)(0\le x,y <p,x\neq y),且aba\bot b,则xy(mod b)x\equiv y(mod\ b)。进一步的,由于0x,y<p0\le x,y <p,则x=yx=y,得出矛盾。
证毕。

这一步是想说明,只要有解,解的范围就在[0,b/d1][0,b/d-1]中。而mb<ax+ta(b1)+a=ab,(m+1)b<ab+b1018+109<1020mb<ax+t\le a(b-1)+a=ab,(m+1)b<ab+b\le 10^{18}+10^9<10^{20}
这回是真的结束了。

代码:

#include <cstdio>
#include <cctype>
char ans[2][10]={"NO\n", "YES\n"};

int gcd(int a,int b) {return b?gcd(b, a%b):a;}
int read()
{
	int res=0;
	char ch=getchar();
	while(!isdigit(ch))	
		ch=getchar();
	while(isdigit(ch))
		res=res*10+ch-'0',ch=getchar();
	return res;
}
int main()
{
	int T=read();
	while(T--)
	{
		int a=read(),b=read(),k=read();
		if (a>b)
			a^=b^=a^=b;
		if (k==1)
			printf("%s",ans[0]);
		else
		{
			int d=gcd(a, b),r=b%a;
			int s=(b-1)/a+(r>d);
			printf("%s",ans[s<k]);
		}
	}
	return 0;
}