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性质、质因子的角度去思考,而不是想通过乱搞(少数)去解决(数学还是太折磨了)

posted @ 2021-01-12 21:16  Lecoww  阅读(101)  评论(1编辑  收藏  举报