2021CCPC华为云挑战赛-1006 仓颉造数
赛时没做出来,16:00结束当我推出大概结论的时候已经16:02了,这里还是打算把题解写一下,因为感觉官方题解概括性很强所以部分同学 (指我这个菜鸡) 可能看不懂,所以这里写一些自己的思路
另外因为HDUOJ挂了,大家看看题看看思路就好可以简单想想做法,(或者等HDU修好)
前方大量数学公式预警
传送门
题目大意
因为是中文题目,所以就不写了(咕)
解题思路
先说最终结论:对ba约分后,若满足a+b=2m,则能够合成1。
(官方题解有写,这里给出貌似也没啥用)
实际上那个999999999999比较大所以不用管天数……
下述证明过程中只使用了2x+y,没有使用x+y2xy,理由是:
x+y2xy等价于x1+y12 所以当我们要求出1时 只需要x+y=2(由式1推得)或x1+y1=2(由式2推得) 而如果我们可以得出x,则一定也可以得到它的倒数x1 原因是:我们得初值ba和ab互为倒数, 并且将其带入到式1和式2中会得到a2+b22ab和2aba2+b2也互为倒数 我们可以选择其中任意一个表达式选取我们所需要的结果
首先证明下面一个结论:在任意一天,我们获得的数一定满足如下表达式(该表达式可以通过手算得到规律)
(x+y)abxa2+yb2,其中x+y=2m
证明前同时给出该公式的另一表达形式,方便看懂后面的部分:
(x+y)abxa2+yb2,其中x+y=2m⇒tabxa2+(t−x)b2,其中x+y=2m=t
证明:利用数学归纳法的思想
-
在第0天的时候,ba和ab分别是上述表达式在x=1,y=0和x=0,y=1时的特例。
-
在以后的某一天当中,我选取的任意两个数一定满足上述表达式,则
2t1abx1a2+(t1−x1)b2+t2abx2a2+(t2−x2)b2(计算两项之和) =2t1t2abx1t2a2+(t1t2−x1t2)b2+x2t1a2+(t1t2−x2t1)b2(通分) =2t1t2ab(x1t2+x2t1)a2+(2t1t2−(x1t2+x2t1))b2(合并同类型) 令X=x1t2+x2t1,T=2t1t2,则上述表达式可以进一步化简为: TabXa2+(T−X)b2(看上去就舒服多了) 而此时我们可以发现T=2t1t2=2⋅2m1⋅2m2=2m1+m2+1=X+Y 即新得到的表达式也满足条件
综上,可以得出结论,得到的所有数字均满足上述表达式,证毕。
有了上述结论,我们就可以进行下一步的证明。
首先,初始获得的是数字ba和ab,我们先对其进行约分,后面的证明需要用到
a /= __gcd(a,b); b /= __gcd(a,b);
由于我的目的是合成1,所以让某一天获得的数字等于1即可,即对下面的表达式进行化简:
(x+y)abxa2+yb2=1 ⇒xa2+yb2−xab−yab=0 ⇒x(a2−ab)+y(b2−ab)=0 ⇒(xa−yb)(a−b)=0 ⇒a=b 或 xa=yb a=b可以看成xa=yb的特殊条件 有ba=xy 同时由于ba为既约分数,且可以证明xy也为既约分数(见下) 即可得到a=y,b=x 由于x+y=2m,即a+b=2m
下面证明xy为既约分数:
证明 :
若x,y含有2以外的公因子,这与x+y=2m矛盾若x.y均为偶数,则在计算时就已经与x+y进行约分所以gcd(x,y)=1
证毕。
至此全部证明结束。
AC代码
代码中用lowbit
判断是否为2的幂次
#include <bits/stdc++.h>
typedef long long llong;
typedef unsigned long long ullong;
const int N = 1e5 + 5;
using namespace std;
int a, b;
int main() {
#ifdef LOCAL
freopen("E:/code/ACM/in.in", "r", stdin);
freopen("E:/code/ACM/out.out", "w", stdout);
#endif
int T; scanf("%d", &T);
while (T--) {
scanf("%d%d", &a, &b);
int x = __gcd(a, b);
a /= x; b /= x;
puts((((a + b) & -(a + b)) == (a + b)) ? "Yes" : "No");
}
return 0;
}