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

  • 相关阅读:
    多点触控(包括拖拽控件)的例子
    绑定当前对象例子——Tag="{Binding}"
    绑定自己Self
    按键(ESC ,F1,F2等)——wpf的命令处理方法
    C#基础:值类型、引用类型与ref关键字
    生成事件命令
    Prism——Region
    组合模式的一个案例说明
    Laravel 学习记录
    【Linux学习】3.Linux常见配置文件
  • 原文地址:https://www.cnblogs.com/ruanbaiQAQ/p/14269335.html
Copyright © 2011-2022 走看看