计蒜客 ACM-ICPC Nanjing Onsite 2018 J. Prime Game(数论)

这篇博客介绍了计蒜客 ACM-ICPC Nanjing Onsite 2018 中的J题——Prime Game,涉及数论知识点。题目要求计算数组a中元素的质因数个数之和的特定组合。解决方案分析了数组元素对整体值的贡献,分为质因子首次出现和非首次出现两种情况,并提供了O(nlogn)时间复杂度的算法思路和AC代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

计蒜客 ACM-ICPC Nanjing Onsite 2018 J. Prime Game(数论)

题目链接:https://nanti.jisuanke.com/t/A2147
题目大意:给定一组长度为 n n n 的数组 a a a ,求 ∑ i = 1 n ∑ j = i n f a c ( ∏ k = i j a k ) \sum\limits_{i=1}^{n}\sum\limits_{j=i}^nfac(\prod\limits_{k=i}^ja_k) i=1nj=infac(k=ijak) 的值。其中 f a c ( x ) fac(x) fac(x) 的值为 x x x 的质因数个数。
题解:考虑 a r a_r ar 对于整体值的贡献。显然, a r a_r ar 只能对 ∑ i = 1 r ∑ j = r n f a c ( ∏ k = i j a i ) \sum\limits_{i=1}^{r}\sum\limits_{j=r}^nfac(\prod\limits_{k=i}^ja_i) i=1rj=rnfac(k=ijai) 这一部分的值进行影响。不难看出,这一部分共包含了 r r r 行和 n − r + 1 n-r+1 nr+1 列,是一个 r ∗ ( n − r + 1 ) r*(n-r+1) r(nr+1) 的矩形。
对于 a r a_r ar 的每一个质因子,有两种情况。
①:这个质因子是第一次出现。那么此时这个质因子对答案的贡献就为 r ∗ ( n − r + 1 ) r*(n-r+1) r(nr+1)
②:这个质因子并不是第一次出现。如果我们知道这个质因子上一次出现的行位置 p o s pos pos ,那么这个质因子对答案的贡献就是 ( r − p o s ) ∗ ( n − r + 1 ) (r-pos)*(n-r+1) (rpos)(nr+1)
算法此时的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn) (遍历 n n n 个数并对每个数进行因数分解)。下面是AC代码。

#include<iostream>
#include<vector>
#include<unordered_map>
using namespace std;
#define debug(x) cerr<<#x<<":"<<x<<endl
#define debug2(x,y) cerr<<#x<<":"<<x<<"  "<<#y<<":"<<y<<endl
#define debug3(x,y,z) cerr<<#x<<":"<<x<<"  "<<#y<<":"<<y<<"  "<<#z<<":"<<z<<endl
typedef long long ll;
struct fastio{
    fastio(){
        ios::sync_with_stdio(0);
        cin.tie(0);
        cout.tie(0);
    }
}fio;
const int N=1e6+5;
vector<int> prime,part;
void init(){
    part=vector<int>(N,0);
    part[1]=1;
    for(int i=2;i<N;++i){
        if(!part[i]){
            prime.push_back(i);
            part[i]=i;
        }
        for(auto j:prime){
            if(i*j>=N) break;
            part[i*j]=j;
            if(i%j==0) break;
        }
    }
}
ll solve(const vector<int>& data){
    ll r=0,res=0;
    unordered_map<int,int> pos;
    for(int i:data){
        while(i>1){
            int p=part[i];
            while(p==part[i]) i/=p;
            if(!pos.count(p)) res+=(r+1)*(data.size()-r);
            else res+=(r-pos[p])*(data.size()-r);
            pos[p]=r;
        }
        ++r;
    }
    return res;
}
signed main(){
    init();
    int n,m;
    vector<int> data;
    cin>>n;
    while(n--){
        cin>>m;
        data.push_back(m);
    }
    cout<<solve(data)<<endl;
}

弄了大约一个半小时才AC。。。还要继续多加努力。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值