zoukankan      html  css  js  c++  java
  • Codeforces Round #694 (Div. 2) D 题题解

    《 离 散 数 学 学 疯 以 后 》

    传送门


    【题目大意】

    定义关系 (R) ,若 ( ext{lcm}(x,y)over gcd(x,y)) 为完全平方数,则 (x R y)

    现给定长度为 (n) 的序列 (a) 。每次操作会将元素 (a_i) 替换为所有与之具有关系 (R) 的元素的乘积(包括它自己),即 (a_ileftarrow displaystyle prod_{a_i R a_j}a_j)

    另外定义 (d_i) 表示与 (a_i) 具有关系 (R) 的元素的个数,定义序列的特征为 (d_i) 的最大值。

    现有 (q) 个询问,每次询问给定 (w) ,输出 (w) 次操作后的序列的特征值。


    【分析】

    (ecause ext{lcm}(x,y)={xyover gcd(x,y)})

    ( herefore { ext{lcm}(x,y)over gcd(x,y)}={xyover gcd(x,y)^2})

    (ecause gcd(x,y)^2) 为完全平方数

    ( herefore {xyover gcd(x,y)^2}) 为完全平方数 (Leftrightarrow) (xy) 为完全平方数

    即若 (xy) 为完全平方数,则 (x R y)

    不难发现,关系 (R) 具有以下三个特性:

    1. 自反性:(x^2) 为完全平方数 (Rightarrow) (x R x)
    2. 对称性:(x R y) (Rightarrow) (xy) 为完全平方数 (Rightarrow) (y R x)
    3. 传递性:(x R ywedge y R z) (Rightarrow) (xy,yz) 为完全平方数 (Rightarrow) (xzy^2=xycdot yz) 为完全平方数
      (ecause y^2) 为完全平方数 ( herefore xz) 为完全平方数 (Rightarrow) (x R z)

    因此关系 (R) 为等价关系,能将序列 (a) 分为若干等价类

    因此,序列的特征等价于所有等价类大小的最大值;每次操作相当于将等价类内部的元素,替换成等价类所有元素的乘积


    对于一个等价类 (P) ,由唯一质数分解定理,一定存在一个各质因子次数都不大于 (1) 的数 (r) ,使得 (forall xin Pleftrightarrow (exist nin Nwedge x=rcdot n^2))

    证明:设 (exist x,yin P,nin Nwedge x=rcdot n^2)

    (ecause xy=rycdot n^2) 为完全平方数,(n^2) 为完全平方数

    ( herefore ry) 为完全平方数

    (ecause r) 各质因子次数不大于 (1)

    ( herefore y=rcdot m^2,min N)

    因此各等价类可由各自的 (r) 作为其特征


    对于一个等价类 (P) ,若 (|P|) 为偶数,则一次变化后,特征 (r) 变为 (1) ;若 (|P|) 为奇数,则一次变化后,特征 (r) 不变

    因此,第一次操作前,序列的特征为最大的等价类

    第一次操作后,原长度为偶数的等价类与原特征为 (1) 的等价类合并,原长度为奇数的等价类不变;序列的特征或为原长度为偶数的等价类大小,与原特征为 (1) 的等价类大小之和,或为长度为奇数的等价类大小

    第二次操作及之后,等价类不再发生变化,答案不变

    故仅需预处理第一次变化前的各等价类大小,即可预处理出第一次操作前后的答案,从而得出所有答案


    【代码】

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int MAXN=3e5+10;
    int N;
    map<int,int> m;
    inline void work(){
        m.clear();
        cin>>N;
        for(int i=1;i<=N;i++){
            int A;
            cin>>A;
            for(int j=2;j*j<=A;j++)//找出对应的 r
                while(A%(j*j)==0) A/=j*j;
            ++m[A];//记录至等价类
        }
        int Ans0=0,Ansodd=0,Ans1=0;
        for(auto e : m){
            Ans0=max(Ans0,e.second);//等价类大小最大值,w=0时的答案
            if(e.second&1) Ansodd=max(Ansodd,e.second);//等价类大小为奇数的最大值
            else Ans1+=e.second;//第一次操作后,等价类大小为偶数的合并
        }
        if(m[1]&1) Ans1+=m[1];//特征为 1 的等价类还未合并
        Ans1=max(Ans1,Ansodd);//w>0 时的答案
    
        ll Q,W;
        cin>>Q;
        while(Q--&&cin>>W)
            if(W) cout<<Ans1<<"
    ";
            else cout<<Ans0<<"
    ";
    }
    int main(){
        ios::sync_with_stdio(0);
        cin.tie(0); cout.tie(0);
        int T;
        cin>>T;
        while(T--) work();
        cout.flush();
        return 0;
    }
    
  • 相关阅读:
    css 超出两行省略号,超出一行省略号
    css 去掉i标签默认斜体样式
    Spring 使用单选按钮
    Spring Maven工程引入css,js
    Sping 补充完成修改功能
    Spring 控制器层如何启用验证?
    Spring 控制器层如何调用DAO层
    spring boot工程如何启用 热启动功能
    Spring 视图层如何显示验证消息提示
    Sping POJO中如何添加验证规则和验证消息提示
  • 原文地址:https://www.cnblogs.com/JustinRochester/p/14240313.html
Copyright © 2011-2022 走看看