Codeforces | CF1033D 【Divisors】

题目大意:给定\(n(1\leq n\leq500)\)个数\(a_1,a_2\cdots,a_n(1\leq a_i\leq2\cdot10^{18})\),每个数有\(3\sim5\)个因数,求\(\prod_{i=1}^{n}a_i\)的因数个数
这道题是一个交互题(虽说并不觉得有交互的必要...可能只是为了\(hack\)或者造数据方便吧),非常纯的数\((du)\)学\((liu)\),题目难度不在于结论,而在于代码实现
小学数学告诉我们以下结论:一个正整数\(x\)可以被分解成唯一形式\(x=p_{1}^{a_{1}}\cdot p_{2}^{a_{2}}\cdot \cdots \cdot p_{k}^{a_{k}}(p_i\text{为质数})\),\(x\)的因数个数为\(\prod_{i=1}^{k}(a_i+1)\).所以这道题的本质是质因数分解.
对于一个数\(x\)进行质因数分解最快的方式是枚举\(2\sim\sqrt{x}\)的质数\(p\)判断\(p\)是否能整除\(x\)进行分解,但是题目数据范围\(a_i\leq10^{18}\),如果要对\(a_i\)直接质因数分解需要枚举\(2\sim10^9\)内所有质数,若按照这种思路还需要预处理\(10^9\)内的质数表.
但是这样做并不可行,\(10^9\)内的质数表即使用线性筛也无法在\(1s\)和\(256M\)的限制内完成.此时注意到题目上还有未使用到的条件:每个数有\(3\sim5\)个因数.所以此题唯一的入手点就是这个具有奇特性质的条件.
考虑一个数\(x\)有\(3\sim5\)个因数可能的特殊性质,发现\(x\)有\((1)p_1\cdot p_2,(2)p_1^2,(3)p_1^3,(4)p_1^4\)四种可能的分解形式,对于\((2)(3)(4)\)三种分解形式,我们可以考虑二分求出\(p_1\)(\(cmath\)并不支持求\(\sqrt[3]{x},\sqrt[4]{x}\)),如果满足\((2)(3)(4)\)中任意一种分解,那么直接计数即可,如果三种分解形式都不满足,那么考虑对于\(p_1\cdot p_2\)形式的数的分解,如果\(p_1,p_2\)的次数都为\(1\)那么可以不分解这样的\(x\),直接乘\(2\times2\),如果\(p_1,p_2\)的次数有至少一个不为\(1\),那么对于\(x\)一定存在一个数\(y(y\neq x)\)使得\(gcd(x,y)>1\),此时的\(gcd(x,y)\)就是\(x,y\)的一个质因数,也即\(x,y\)都完成了质因数分解.至此所有可分解的数都完成了质因数分解,不可分解的数都满足两个质因数次数为\(1\),所以剩下的只需要求\(\prod_{i=1}^{k}(a_i+1)\)即可.
下面放\(AC\)代码\(\downarrow\downarrow\downarrow\)

#include<cstdio>//CF1033D
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<map>

using namespace std;

const int MOD=998244353;

int n;

long long a[502];

map<long long,long long>mp,mmp;

long long gcd(long long u,long long v){
    if(v==0){
        return u;
    }
    return gcd(v,u%v);
}

long long bs2(long long l,long long r,long long u){
    if(l==r){
        return l;
    }
    long long mid=(l+r)>>1;
    if(mid*mid<u){
        return bs2(mid+1,r,u);
    }
    else{
        return bs2(l,mid,u);
    }
}

long long bs3(long long l,long long r,long long u){
    if(l==r){
        return l;
    }
    long long mid=(l+r)>>1;
    if(mid*mid*mid<u){
        return bs3(mid+1,r,u);
    }
    else{
        return bs3(l,mid,u);
    }
}

long long bs4(long long l,long long r,long long u){
    if(l==r){
        return l;
    }
    long long mid=(l+r)>>1;
    if(mid*mid*mid*mid<u){
        return bs4(mid+1,r,u);
    }
    else{
        return bs4(l,mid,u);
    }
}

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    for(int i=1;i<=n;i++){
        long long rep;
        rep=bs4(1,40000,a[i]);
        if(rep*rep*rep*rep==a[i]){
            mp[rep]+=4;
            continue;
        }
        rep=bs3(1,1300000,a[i]);
        if(rep*rep*rep==a[i]){
            mp[rep]+=3;
            continue;
        }
        rep=bs2(1,1500000000,a[i]);
        if(rep*rep==a[i]){
            mp[rep]+=2;
            continue;
        }
        bool flag=false;
        for(auto ite:mp){
            if(a[i]%ite.first==0){
                mp[ite.first]++;
                mp[a[i]/ite.first]++;
                flag=true;
                break;
            }
        }
        if(!flag){
            for(auto ite2:mmp){
                if(ite2.first==a[i]){
                    mmp[a[i]]++;
                    flag=true;
                    break;
                }
                long long g=gcd(a[i],ite2.first);
                if(g>1){
                    mp[g]+=ite2.second+1;
                    mp[a[i]/g]++;
                    mp[ite2.first/g]+=ite2.second;
                    mmp[ite2.first]=0;
                    flag=true;
                    break;
                }
            }
            if(!flag){
                mmp[a[i]]++;
            }
        }
    }
    for(auto ite2:mmp){
        for(auto ite:mp){
            if(ite2.first%ite.first==0){
                mp[ite.first]+=ite2.second;
                mp[ite2.first/ite.first]+=ite2.second;
                mmp[ite2.first]=0;
                break;
            }
        }
    }
    long long ans=1;
    for(auto ite:mp){
        ans*=(ite.second+1);
        ans%=MOD;
    }
    for(auto ite:mmp){
        ans*=(ite.second+1);
        ans%=MOD;
        ans*=(ite.second+1);
        ans%=MOD;
    }
    printf("%lld\n",ans);
    fflush(stdout);
    return 0;
}

原文地址:https://www.cnblogs.com/--BLUESKY007/p/9852590.html

时间: 2024-08-30 17:11:13

Codeforces | CF1033D 【Divisors】的相关文章

Codeforces 479【E】div3

题目链接:http://codeforces.com/problemset/problem/977/E 题意:就是给你相连边,让你求图内有几个环. 题解:我图论很差,一般都不太会做图论的题.QAQ看官方题解过的.大概就是如果这是一个环的话,每一个点的度数都应该是2才对,根据这个进行dfs做标记. 就算是个简单图论,看到还是会一脸懵逼.QWQ.以后还是会多多写dfs和图论啦.不过个人还是更喜欢数论什么的. 1 #include<iostream> 2 #include<vector>

Codeforces | CF1028C 【Rectangles】

(这道题太简单啦...虽说我锤了一上午都没过...我能说这道题和\(CF1029C\)算是同一道题吗...) 按照时间顺序来说...\(CF1029\)在\(CF1028\)前面(而且\(CF1029\)还是\(Div3\)),前后没差多长时间就惊现高相似度题目(所以CF是有多迫切想让大家上分) CF1029C传送门 两道题的唯一差别就是一个是一维,一个是二维(我是不是应该猜一下\(CF1036C\)会出一个三维的),都是范围覆盖,和\(CF1029C\)一样,只需要确定最严格的边界限制,题目要

codeforces 1037E-Trips 【构造】

题目:戳这里 题意:n个点,每天早上会在这n个点中加一条边,每天晚上最大的子图满足子图中每个点都有k条或以上的边. 解题思路:看了官方题解,先把所有的点都连上,再从最后一天往前减边,用set维护最大的子图,注意每减去一条边时,更新该边两端点的状态. 1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 2e5 + 10; 5 int ans[maxn]; 6 st

Codeforces 1030D 【构造】

LINK 题目大意:给你n,m,k,让你在一个n*m的点阵里构造出一个面积为\(\frac{n*m}{k}\)的三角形 思路 首先要有一个结论是整点三角形的面积分母最多为2,然后就可以判断不存在的情况了 接下来就直接进行构造就可以了 #include<bits/stdc++.h> using namespace std; #define LL long long #define IL inline #define fu(a,b,c) for(LL a=b;a<=c;++a) #defin

【模拟】Codeforces 706A Beru-taxi

题目链接: http://codeforces.com/problemset/problem/706/A 题目大意: 家的坐标在sx,sy,有n辆车,每辆车坐标xi,yi,速度vi,问最快的一辆车什么时候到家. 题目思路: [模拟] 签到题. 1 // 2 //by coolxxx 3 // 4 #include<iostream> 5 #include<algorithm> 6 #include<string> 7 #include<iomanip> 8

【模拟】Codeforces 691B s-palindrome

题目链接: http://codeforces.com/problemset/problem/691/B 题目大意: 求一个字符串是不是镜像的(不是回文).是输出TAK否则RE. 题目思路: [模拟] 预处理镜像的字母,注意bd pq,从头尾开始模拟. 1 // 2 //by coolxxx 3 //#include<bits/stdc++.h> 4 #include<iostream> 5 #include<algorithm> 6 #include<strin

【模拟】Codeforces 691C Exponential notation

题目链接: http://codeforces.com/problemset/problem/691/C 题目大意: 输入一个数,把它表示成a·10b形式(aEb).输出aEb,1<=a<10,b如果为1要省略Eb 题目思路: [模拟] 如果字符串没有‘.'我就在最后加上一个'.'方便处理. 先把头尾多余的0去掉,然后把这个数按照'.'拆成两半,统计整数部分的位数zs. 接着统计'.'后面的0的个数xs,再把所有数字放到一个数组里,再把头多余的0去掉(0.0000xx). 之后按照zs和sx的

【模拟】Codeforces 691A Fashion in Berland

题目链接: http://codeforces.com/problemset/problem/691/A 题目大意: n个数0或1,要求恰好n-1个1,如果n为1则那个数一定要是1 题目思路: [模拟] 水题一道.看错题目两次.. 1 // 2 //by coolxxx 3 //#include<bits/stdc++.h> 4 #include<iostream> 5 #include<algorithm> 6 #include<string> 7 #in

【STL】Codeforces 696A Lorenzo Von Matterhorn

题目链接: http://codeforces.com/problemset/problem/696/A 题目大意: 一个满二叉树,深度无限,节点顺序编号,k的儿子是k+k和k+k+1,一开始树上的边权都为0 N(N<=1000)个操作,操作两种,1是从u到v的路径上的所有边权+w,2是求u到v的边权和.(1 ≤ v, u ≤ 1018, v ≠ u, 1 ≤ w ≤ 109) 题目思路: [STL] 用map写很快,第一次用很生疏.现学只看了一点点. 因为是满二叉树所以直接暴力求LCA和求解,