【ACM-ICPC 2018 南京现场赛 】 J.Prime Game ---- 思维+素数筛

题目:
在这里插入图片描述

做法: 计算出来每个数的质因子在各个区间的贡献。
以第二组样例为例:
在这里插入图片描述
第一个元素的素因子2:
它能贡献的区间有[1,1],[1,2],……,[1,10] 10个区间
第一个元素的素因子3:
它能贡献的区间有[1,1],[1,2],……,[1,10] 10个区间
当前sum = 10+10
第二个元素的素因子7:
它能贡献的区间有[1,2],[1,3],……,[1,10] 9个区间
它能贡献的区间有[2,2],[2,3],……,[2,10] 9个区间
当前sum = 10+10 +9*2
同理第三个元素的素因子5算好后 sum = 10+10+9*2+8*3
当考虑第四元素的素因子5时,发现i = 3时的素因子5
在区间:
[1,3],[1,4],……,[1,10]
[2,3],[2,4],……,[2,10]
[3,3],[3,4],……,[3,10]
这3*8个区间中已经贡献过,所以我们从当前i = 4位置向后考虑 这个位置的素因子5对区间的贡献为 7
sum = 10+10+9*2+8*3+7

最终到n = 10,sum = 10+10+9*2+8*3+7+6*4+5*5+4+0+2*4+1+3=134
依次向后推理,我们现在每个素因子i贡献公式为:

a n s i = ( n − p r i m e [ i ] [ p o s ] + 1 ) ∗ ( p r i m e [ i ] [ p o s ] − p r i m e [ i ] [ p o s − 1 ] ) ans_i = (n-prime[i][pos]+1)*(prime[i][pos]-prime[i][pos-1]) ansi=(nprime[i][pos]+1)(prime[i][pos]prime[i][pos1])
所以我们分解出质因子,把他们的位置放进vector, 扫一遍素数即可

代码

#include<bits/stdc++.h>
using namespace std;

#define IO          ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define pb(x)       push_back(x)
#define sz(x)       (int)(x).size()
#define sc(x)       scanf("%d",&x)
#define abs(x)      ((x)<0 ? -(x) : x)
#define all(x)      x.begin(),x.end()
#define mk(x,y)     make_pair(x,y)
#define fin         freopen("in.txt","r",stdin)
#define fout        freopen("out.txt","w",stdout)

typedef long long ll;
const int mod = 1e9+7;
const double PI = 4*atan(1.0);
const int maxm = 1e8+5;
const int maxn = 1e6+5;
const int INF = 0x3f3f3f3f;
const ll LINF = 1ll<<62;

int a[maxn],n,tot;
int prime[maxn];
bool isprime[maxn];
vector<ll> vec[maxn];
void prime_table()
{
    memset(isprime,true,sizeof(isprime));
    isprime[0] = isprime[1] = false;
    for(ll i=2;i<maxn;i++){
        prime[tot++] = i;
        if(isprime[i]){
            for(ll j=i*i;j<maxn;j+=i)
                isprime[j] = false;
        }
    }
}
void dec(int pos)
{
    int t = a[pos];
    for(int j=0;j<tot && prime[j]*prime[j]<=t;j++)
    {
        if(t%prime[j] == 0){
            vec[prime[j]].pb(pos);
            while(t%prime[j] == 0) t/=prime[j];
        }
    }
    if(t>1) vec[t].pb(pos);
}
int main()
{
    // fin;
    IO;
    prime_table();
    cin>>n;
    for(int i=2;i<maxn;i++) vec[i].pb(0);
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++) dec(i);
    ll res = 0;
    for(int i=0;i<tot;i++){
        for(int j=1;j<sz(vec[prime[i]]);j++){
            res = res+1ll*(vec[prime[i]][j] - vec[prime[i]][j-1])*1ll*(n-vec[prime[i]][j]+1); 
        }
    }
    cout<<res<<endl;
    return 0;
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值