2018-2019 Asia Nanjing Regional Contest练习总结

题目:Prime Game

题意:

给出一个序列,定义了 mul(l, r) 为 al 到ar 的乘积,而fac(l, r) 为mul(l, r) 不相同质因数的个数,让你算出这个序列所有子区间的fac和。

思路:

这个主要理清对于序列中的一个数 a,找出它的贡献段,对于序列中任意一个aw ,它说分解出来的每一个不同素数(z),贡献为( w-point[ z ] )* (n-w+1)   【point为存储素数上次出现位置的数组,此处下标从1开始】。有了贡献的计算方法就很好搞了,不过要注意范围,在计数这个贡献时,乘积会爆int (WA在第7个点)。

解题

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
#include <set>
using namespace std;
const long long N = 1e10 + 7;
const int maxn = 1e6 + 5;
const long long INF = 8e18;
typedef long long ll;
#define for0(i,n) for(int i = 0;i < n;i++)
#define for1(i,n) for(int i = 1;i <= n;i++)
int point[maxn];  // 存该素数上次的出现位置
int prime_if[maxn];
int prime[maxn],x;
void oulasai(int n)
{
    prime_if[1] = 1;
    for(ll i=2;i<=n;i++)
    {
        if(!prime_if[i])
            prime[x++]=i;
        for(int j=0;j<x;j++)
        {
            if(i*prime[j]>n)
                break;
            prime_if[i*prime[j]]=1;
            if(i%prime[j]==0)
               break;
        }
    }
}

int main()
{
    //ios::sync_with_stdio(false);
    oulasai(maxn);
    int n;
    cin >> n;
    ll sum = 0;
    for1(i,n){
        int y;
        cin >> y;
        if(y == 1)
            continue;
        if(prime_if[y]){
            for(int j = 0;j < x;j++){
                if(prime[j] * prime[j] > y)
                    break;
                if(y % prime[j] == 0){

                    sum += (ll)(n-i+1) * (i-point[prime[j]]);
                    point[ prime[j] ] = i;
                    while(y % prime[j] == 0)
                        y /= prime[j];

                }

            }
        }
        if(!prime_if[y]){  //最后一次出现的素数
            sum += (ll)(n-i+1)*(i-point[y]);
            point[y] = i;

        }
    }
    cout << sum << endl;

    return 0;
}

 

posted @ 2020-12-01 17:38  emhhbw==  阅读(127)  评论(0)    收藏  举报