传送门:https://codeforces.com/contest/1471/problem/D
一、题意:
在一组长度为n的数组中,如果存在a[i],a[j]满足lcm(a[i],a[j])/gcd(a[i],a[j]) 为一个完美开方数,则称a[i]与a[j]为相邻数(j可以等于i)。
di为与a[i]为相邻数的数字个数,每秒钟会将同类的相邻数相乘并代替原数字。
如20,5,80为一组相邻数,一秒后就变为8000,8000,8000。
接下来有q次询问,每次输入一个w,问w秒后d的最大值。
二、思路:
1.lcm(x,y)=xy/gcd(x,y)
2.lcm(x,y)/gcd(x,y)=xy/gcd(x,y)2
容易看出当xy为完美开方数时能够符合条件。
可以将x和y分解为自身的质因数的平方相乘,分解到最后如果x==y则xy为同类,详情见代码
for (int i = 1; i <= n; i++) {
scanf("%d", &x);
for (int j = 2; j*j <= x; j++)
while (x % (j*j) == 0)x /= (j*j);
m[x]++//(记录同类数的个数);
}
0秒时最大值就是记录下来的同类数个数,1秒之后则不变。
因为当m[x]为奇数时,说明该类有奇数个元素,相乘之后类型依然不变。
如20,45,80通过上述步骤分解后为都变为5,相乘之后为72000,72000分解后依然是5。
当m[x]为偶数时,相乘之后类型发生改变。
如20,45,80,125分解后变为5,相乘之后为9000000,分解后为1。
所以在一秒之后,类型都不再发生改变。所以在第一次统计之后,将m[x]为偶数的个数与m[1]合并,奇数不变,再次统计个数,详情见代码
int ans1 = 0,ans2=0,ansodd=0;
for (auto e : m) {
ans1 = max(ans1, e.second);//统计0秒时的最大值
if (e.second & 1) { ansodd = max(ansodd, e.second); }//如果为奇数个,用ansodd统计最大值
else ans2 +=e.second;//如果是偶数,将其合并为同类
}
if (m[1]&1)ans2 += m[1];//将还未合并1类的合并
ans2 = max(ans2, ansodd);
完整代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<queue>
#include<vector>
#include<stack>
#define ll long long
using namespace std;
const int inf = 1e9 + 7;
map<int, int>m;
int main()
{
int t;
scanf("%d", &t);
while (t--) {
m.clear();
int n;
scanf("%d", &n);
int x;
for (int i = 1; i <= n; i++) {
scanf("%d", &x);
for (int j = 2; j*j <= x; j++)
while (x % (j*j) == 0)x /= (j*j);
m[x]++;
}
int ans1 = 0,ans2=0,ansodd=0;
for (auto e : m) {
ans1 = max(ans1, e.second);//统计0秒时的最大值
if (e.second & 1) { ansodd = max(ansodd, e.second); }//如果为奇数个,用ansodd统计最大值
else ans2 +=e.second;//如果是偶数,将其合并为同类
}
if (m[1]&1)ans2 += m[1];//将还未合并1类的合并
ans2 = max(ans2, ansodd);
ll q, w;
scanf("%lld", &q);
while (q--) {
scanf("%lld", &w);
if (w)printf("%d\n", ans2);
else
printf("%d\n", ans1);
}
}
return 0;
}