• Codeforces 980 D. Perfect Groups


    (>Codeforcesspace980 D. Perfect Groups<)

    题目大意 : 设 (F(S)) 表示在集合(S)中把元素划分成若干组,使得每组内元素两两相乘的结果的都是完全平方数的最小组数

    对于长度为(n)的序列 (A) ,对于每一个 (k \, (1 leq k leq n)) ,分别求出在(A)的所有子串中有多少 ([l, r]) 满足 (F(A[l, r]) = k)

    $n leq 5000, space |A_{i}| leq 10^9 $

    解题思路 :

    先考虑如何求出 (F(S)) ,发现对于一个满足要求的组,对组内元素分解质因数后,每一个质因子出现次数的奇偶性相同

    证明: 如果两数相乘是平方数,设这个数为 (p_{1}^{k1} imes p_{2}^{k2} imes.. imes p_{n} ^{kn} (p is prime)),必然对于所有 (k) ,满足(k equiv 0 pmod {2})

    又因为当且仅当奇偶性相同的两个数相加才能变成偶数,所以对于组内的每一个数分解质因数后质因子出现次数的奇偶性相同

    观察发现,出现次数为偶数的质因子出现与否并不影响答案,所以可以直接消去,对于所有出现次数为奇数的质因子,也只需要保留一个即可,这样做等价于将数中的所有平方因子全部消去

    将问题回到序列上,发现消去平方因子后如果两个数 (a,b) 能分到一组,当且仅当 (a = b) ,问题就转变为区间不同的数的个数,直接暴力统计即可,注意特判 (0) 可以放到任意组。


    /*program by mangoyang*/
    #include<bits/stdc++.h>
    #define inf (0x7f7f7f7f)
    #define Max(a, b) ((a) > (b) ? (a) : (b))
    #define Min(a, b) ((a) < (b) ? (a) : (b))
    typedef long long ll;
    using namespace std;
    template <class T>
    inline void read(T &x){
        int f = 0, ch = 0; x = 0;
        for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
        for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
        if(f) x = -x;
    }
    #define N (100005)
    #define int ll
    struct Point{ int x, id; } e[N];
    int a[N], buf[N], Ans[N], n, col, f0;
    inline bool cmp(Point A, Point B){ return A.x < B.x; }
    inline int change(int x){
        int res = x;
        for(int i = 2; i * i <= abs(x); i++)
            while(res % (i * i) == 0) res /= i * i;
        return res;
    }
    main(){
        read(n);
        for(int i = 1; i <= n; i++) read(a[i]), a[i] = change(a[i]);
        for(int i = 1; i <= n; i++) e[i].x = a[i], e[i].id = i;
        sort(e + 1, e + n + 1, cmp);
        a[e[1].id] = ++col; if(e[1].x == 0) f0 = 1;
        for(int i = 2; i <= n; a[e[i++].id] = col){
            if(e[i].x > e[i-1].x) col++;
            if(e[i].x == 0) f0 = col;    
        }
        for(int i = 1; i <= n; i++){
            int res = 0;
            for(int j = i; j <= n; j++){
                if(!buf[a[j]] && a[j] != f0) res++;
                buf[a[j]]++;
                if(!res) Ans[1]++; else Ans[res]++;
            }
            for(int j = i; j <= n; j++) buf[a[j]]--;
        }
        for(int i = 1; i <= n; i++) cout << Ans[i] << " ";
        return 0;
    }
    
  • 相关阅读:
    centos7配置ntp服务器和客户端同步
    搭建Loki、Promtail、Grafana轻量级日志系统(centos7)
    DBLink实现备份文件不落盘的导入其他Oracle数据库实例的方法
    jumpserver使用docker安装
    shellwhile循环读取文件内容
    WEB数据挖掘(八)——Aperture数据抽取(4):Aperture整体结构
    WEB数据挖掘(十)——Aperture数据抽取(6):在Aperture中使用RDF2Go
    matlab练习程序(五次多项式轨迹规划)
    Android与Windows 7比拼悄然开始
    谷歌称年底前至少有18款Android手机上市
  • 原文地址:https://www.cnblogs.com/mangoyang/p/9299757.html
Copyright © 2020-2023  润新知