一开始完全没有思路,和学长交流过以后,对质因数分解有了更深的理解了,是很棒的理解的题目哦!学长的题解比较简洁,我不知不觉写得很详细了,就贴出来吧
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
int T,n,x,y,revise,keyrev;
ll tmp,gcd,lcm,revgcd,revlcm;
/* http://codeforces.com/gym/226005/problem/G
* 这题要用到质因数分解的思路,我觉得蛮重要的
* 首先要知道所有数都可以分解成一系列质数的积,其中相同的质因数可以合并成幂指数
* 多个数的gcd,就是这些同底指数取最小值的幂的乘积,而lcm是最大值的情况
*
* 这题要求所给的数组的整体gcd==x,lcm==y,求最少要求改多少才能达成条件
* 最理想情况是,逐项求gcd,lcm,都满足条件。
* 考虑一种意外,x不是ai的因子,y不是ai的倍数,这是格格不入的一个数,肯定要修改
* 这样所有数读一遍,求出符合x是ai的因子,y是ai的倍数的数组的总体gcd和lcm,并统计revise的数量
*
* 但是这个时候,还需要注意,此时的gcd和x,lcm和y不一定就相等
* 举个例子,revise=0,但是gcd!=x,lcm!=y,这种情况还需要修改,我们记作keyrev
* 这样的情况怎么修改呢?
* 由gcd是取质因子指数最小的乘积,gcd!=x说明需要一个数使得因子的最小值满足x的情况
* 同理也需要一个数, 使得因子的最小值满足y的情况
*
* 这样可以想到,至少需要keyrev=2个数字修改
* 但是如果,需要改变指数最小值的质因子 和 需要改变指数最大值的质因子 没有是不同的呢?
* 那么只需要修改一个数字,同时包含最小和最大指数的质因子就Ok啦
*
* 分析几个小样例:(gcd,lcm表示当前满足tmp%x==0&&y%tmp==0的总值)
* #1:
* 2 30 900
* 90 450
* 90= 2^1 * 3^2 * 5^1;
* 450= 2^1 * 3^2 * 5^2;
* gcd= 2^1 * 3^2 * 5^1 = 90;
* lcm= 2^1 * 3^2 * 5^2 = 450;
* x= 2^1 * 3^1 * 5^1 = 30;
* 需要修改一个数,使得3的最小指数为1;
* y=2^2 * 3^2 * 5^2 = 450;
* 需要修改一个数,使得2的最大指数为2;
* 这时候,两个质因子是不重合的,可以同时改变2的最大指数,3的最小指数。
* 所以试试看把90改成60,是不是就满足条件啦?
*
* #2:
* 4 1 900
* 5 30 180 7
* 5= 2^0 * 3^0 * 5^1;
* 30= 2^1 * 3^1 * 5^1;
* 180= 2^2 * 3^2 * 5^1;
* 7= 7^1;(不可能凑出满足xy的情况,必修改)
* gcd= 2^0 * 3^0 * 5^1 = 5;
* lcm= 2^2 * 3^2 * 5^1 =180;
* x= 2^0 * 3^0 * 5^0 = 1;
* 需要修改一个数,使得5的最小指数为0;
* y= 2^2 * 3^2 * 5^2 = 900;
* 需要修改一个数,使得5的最大指数为2;
* 显然只修改一个指数是不够的呀,那就只能修改两个了!
* (而不是只修改7数字)
*
* 这道题也就是把每个数字都看成一列质因数的乘积!这样想下去就会慢慢清晰啦!
*/
int main()
{
scanf("%d",&T);
while(T--)
{
keyrev=revise=0;
gcd=lcm=0;
scanf("%d %d %d ",&n,&x,&y);
for(int i=1;i<=n;i++)
{
scanf("%d",&tmp);
if(tmp%x==0&&y%tmp==0){
if(!gcd&&!lcm){
gcd=lcm=tmp;
} else {
gcd=__gcd(gcd,tmp);//gcd表示当前满足x,y的数字的gcd
lcm=lcm*tmp/__gcd(lcm,tmp);//同理
}
} else //不满足x,y就是必须要修改了
revise++;
}
//printf("%d %d\n",x,y);
if((n==1&&x!=y)||y%x!=0)puts("-1");
else if(!gcd||!lcm)printf("%d\n",revise);
else {
keyrev=2;//默认假设需要两处关键修改,使得整体gcd==x,lcm==y
revgcd=gcd/x;//为了达到整体gcd为x,需要修改掉的多余的因子
revlcm=y/lcm;//为了达到整体lcm为y,需要修改加上还差的因子
if(gcd==x&&lcm==y){//已经达到x,y 不需要关键修改了
keyrev=0;
} else if(__gcd(revgcd,revlcm)==1){//两个因子没有重合部分,可以通过修改一个数字,使得质因子的max与min都满足
keyrev=1;
}//因子有重合部分,只修改一个不能同时调整质因子的min和max,所以是默认的修改两次~
printf("%d\n",max(revise,keyrev));
}
}
return 0;
}