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

题意描述:给你(n)个数,定义假设对于某个集合,里面任意两数(lcm(x,y)/gcd(x,y))为完全平方数即合法,把这n个数变成为很多这样的集合(每个数只能用1次)。
最开始给的n个数为第0秒,每一秒钟之后,每个集合内的每一个数会变为该集合所有数的乘积,现在有(q)次询问,问你在(w)秒时其中最大的集合的大小。
(1<=n<=3e5)
(1<=a<=1e6)
(1<=q<=3e5)
(0<=w<=1e18)

做法:(lcm(x,y)/gcd(x,y)=x*y/(gcd(x,y)*gcd(x,y))),即xy的乘积除以(gcd(x,y))的平方。那么满足这种情况的两数,它们相乘之后每个质因子的数量都得是偶数:

那么我们通过质因数分解每一个(x),把(x)的数量为奇数的质因子乘在一起,这样得到一个(res),当另一个数(y)要与(x)满足条件是,(y)的数量为奇数的质因子乘在一起也必然是(res)

对于之前每一个(res)出现了多少次取一个max,得到的就是第(0)秒的答案(ans0)


之后每个集合内的每一个数会变为该集合所有数的乘积,若集合的大小为奇数,则他们的乘积质因数分解之后还是原来res,若为偶数则(res)变为(1),可以合并到(res=1)的情况。这样第一秒时就只剩那些集合大小为奇数的(res!=1)的集合以及(res=1)的集合,易知之后不管过了多少秒,答案都不会改变。

细节处理:①有时候最后(res!=1)的集合大小反而大于(res=1)时集合的大小,需要两个之前取一个max。②一般是遍历每一个(res)去找偶数大小的集合,(res=1)的时候集合大小也可能为偶数,不要加重复了。

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL)
double pi = acos(-1);
const double eps = 1e-7;
const int inf = 1e9 + 7;
const int maxn = 1e6 + 10;
ll mod = 1000000007;

map<int, int>mp;

int v[maxn], p[maxn], cnt;

void Euler_sieve(int n)
{
    cnt = 0;
    for (int i = 2; i <= n; i++) {
        if (v[i] == 0) { v[i] = i; p[++cnt] = i; }
        for (int j = 1; j <= cnt; j++)
        {
            if (p[j] > v[i] || p[j] > n / i)break;
            v[i * p[j]] = p[j];
        }
    }
}

int main()
{
    fastio;
    int t;
    cin >> t;
    Euler_sieve(1e6 + 5);
    while (t--)
    {
        mp.clear();
        int n;
        cin >> n;
        int ans1 = 0, ans2 = 0;
        for (int i = 1; i <= n; i++)
        {
            int x;
            cin >> x;
            int res = 1;
            while (x > 1)
            {
                int tot = 0;
                int tmp = v[x];
                while (x % tmp == 0)
                {
                    x /= tmp;
                    tot++;
                }
                if (tot & 1)
                    res *= tmp;
            }
            mp[res]++;
            ans1 = max(mp[res], ans1);
        }
        for (auto i : mp)
            if (i.second % 2 == 0)
                ans2 += i.second;
            else if (i.first == 1)
                ans2 += i.second;
        ans2 = max(ans2, ans1);
        int q;
        cin >> q;
        while (q--)
        {
            ll w;
            cin >> w;
            if (!w)
                cout << ans1 << endl;
            else cout << ans2 << endl;
        }
    }
    return 0;

}

总结:这类数学题大多得去从gcd性质、质因子的角度去思考,而不是想通过乱搞(少数)去解决(数学还是太折磨了)

原文地址:https://www.cnblogs.com/ruanbaiQAQ/p/14269335.html