【Codeforces Round #694 (Div. 1) B】Strange Definition

题目链接

链接

翻译

每秒钟会对原数组进行如下操作,对于每一个数组中的元素。找到整个数组中和它【相关】的数字,将这些数字全都乘起来

然后用来代替这个元素。

【相关】表示两个数字的最小公倍数和最大公因数的商是一个完全平方数。

然后让你回答 \(q\) 个询问,表示 \(w\) 秒钟之后,数组中每个元素【相关】的数字的个数的最大值。

题解

得知道 \(lcm(x,y)=\frac{x*y}{gcd(x,y)}\) 这样的话,就知道两个数字相关当且仅当他们相乘是一个完全平方数(分母已经是 \(gcd\) 的平方了)。

那么什么样的两个数字 \(x\)\(y\) 会满足相乘是一个完全平方数呢?

从质因数分解的角度考虑。

考虑两个数字分解之后所有的 公共 质因子 \(p\),如果两者分解出来的指数 \(q1\)\(q2\) 的和都是偶数。

那么这是它们的乘积是完全平方数的一个先决条件。

还有非公共的部分,这部分咋办? 会发现因为不是公共的质因子,所以如果有一方对应的非公共质因子的指数为奇数。

那么它们相乘就不是完全平方数了,比如 \(2=2\)\(6=2*3\) 其中 \(6\) 的质因子 \(3\) 不是公共质因子,且指数为奇数 \(1\)

所以它们相乘就不是完全平方数了,因此非公共质因子的指数都要为偶数。

而公共质因子的指数相加为偶数,先决条件就是它们俩的指数的奇偶性相同。

也即对应的质因子指数 \(q_i\%2\) 的值要相同。

则我们可以这样,对于数组中所有数字的质因数分解,把它都写成 \(x=p_1^{q_1\%2}*p_2^{q_2\%2}...*p_k^{q_k\%2}\) 的形式。

这样我们就可以根据这个新的 \(p_1^{q_1\%2}*p_2^{q_2\%2}...*p_k^{q_k\%2}\) 标识(运算的结果),相同标识的分到一个集合中去,将原数组中的数字分成很多个不同的集合了。

会发现 同一个集合里面的数字都是互相相关的,相乘之后指数都是偶数。且非公共质因子的指数也用这个模 \(2\) 操作区分开来了,如果为偶数

就直接变成数字 \(1\) 了,不会成为集合的标识。

那么我们就得到很多个集合了,有什么用呢?

一开始 \(0\) 时刻,我们只要统计所有的集合的大小的最大值即可。

大于 \(0\) 时刻,现在要开始变化了。

会发现,如果集合的大小为偶数,那么里面所有的数字相乘的话,最后的结果就是所有新的数字的指数都变成偶数,那么在指数模 \(2\) 的情况下,就全都变成数字 \(1\) 了。

则对应集合会和以 \(1\) 为标识的集合合并到一起。

而集合的大小为奇数的话,那么每个数字的质因子的指数在经过奇数次相加之后,还是一个奇数, 则集合大小不变,里面的数字也不变(指数还是都是 \(1\))。

所以,统计一下 \(1\) 集合,以及集合大小为偶数的集合,记作 \(cnt1\),然后一开始所有集合中大小最大的那个集合的大小,记作 \(cnt2\),这里的 \(cnt2\) 能够覆盖

奇数大小集合不变的情况。

所以在 \(w>=1\) 的时候,输出 \(max(cnt1,cnt2)\) 而在 \(w=0\) 的时候,直接输出 \(cnt2\) 就好,代码中用的不是 \(cnt\) 等名称, 不要 \(confuse\) 了...

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;

int n;
map<int,int> dic;

int main() {
	#ifdef LOCAL_DEFINE
		freopen("in.txt", "r", stdin);
	#endif
	ios::sync_with_stdio(0), cin.tie(0);
	int T;
	cin >> T;
	while (T--) {
        dic.clear();
        cin >> n;
        for (int i = 1;i <= n; i++){
            int x;
            cin >> x;
            for (int j = 2;j*j <= x; j++){
                while (x%(j*j)==0){
                    x/=j*j;
                }
            }
            dic[x]++;
        }
        int a = 0, b = 0;
        for (auto tmp: dic){
            if (tmp.first==1 || tmp.second%2==0){
                b+=tmp.second;
            }
            if (tmp.second > a){
                a = tmp.second;
            }
        }
        int q;
        cin >> q;
        for (int i = 1;i <= q; i++){
            LL w;
            cin >> w;
            if (w == 0){
                cout << a << endl;
            }else{
                cout << max(a,b) << endl;
            }
        }

	}
	return 0;
}
posted @ 2021-01-16 21:41  AWCXV  阅读(84)  评论(0编辑  收藏  举报