J. Prime Game(The 2018 ACM-ICPC Asia Nanjing)(思維+線篩)

J. Prime Game(The 2018 ACM-ICPC Asia Nanjing)(思維+線篩)

Time limit: 2000 ms
Memory limit: 1048576 kB
judge:vjudge

Description

Given a suqence of nn integers aia_i .
Let mul(l,r)mul(l, r) = i=lrai∏^r_{i=l} a_i and fac(l,r)fac(l, r) be the number of distinct prime factors of mul(l,r)mul(l, r).
Please calculate i=1nj=infac(i,j)∑^n_{i=1}∑^n_{j=i}fac(i, j)

Input

The first line contains one integer n(1n106)n (1 ≤ n ≤ 10^6) — the length of the sequence.
The second line contains nn integers ai(1in,1ai106)a_i (1 ≤ i ≤ n, 1 ≤ a_i ≤ 10^6) — the sequence.

Output

Print the answer to the equation.

Examples

standard input

10
99 62 10 47 53 9 83 33 15 24
10
6 7 5 5 4 9 9 1 8 12

standard output

248
134

題意

給你兩個函數:
mul(l,r)=i=lraimul(l, r)=∏^r_{i=l} a_i
fac(l,r)=mul(l,r)fac(l,r)=mul(l,r)的素因子的個數
讓你求解:
i=1nj=infac(i,j)∑^n_{i=1}∑^n_{j=i}fac(i, j)

題意

剛看到這題的時候嚇壞了:我的天、素數、1e6、還累乘、求和後再求和……

但是仔細一想好像有點變化。

把每個數字看成一系列素數的集合,集合裏的素數都是它的因子,那麼兩個數相乘之後他們的素因子的集合就相當於把原來兩個數字對應的素數因子的集合合併到了一起。

我們不要把序列裏的數字看成整體,換個角度:把每個素數對答案做出的貢獻看成一個整體,我們枚舉所有出現過的素數,分別計算貢獻,最後求和即可。

那麼每個素數的貢獻就是包含它的區間的個數,如果區間內包含多個相同的素數,貢獻不疊加計算,算作一個區間。如圖:

假設序列所有的素因子一共有k個,用 pos[x][i]pos[x][i] 表示素數 xx 出現的第 ii 個位置 (0i)(0≤i) 。那麼2出現的位置有這些:0,4,8,9.
在這裏插入圖片描述
2對答案做出的貢獻:43
在這裏插入圖片描述
根據這張圖相信不難看出規律,,那麼答案就是:
ans=i=0k1xij=0pos[xi].size()1(pos[xi][j](j ? pos[xi][j1]:1))(npos[xi][j])ans=∑^{k-1}_{i=0}x_i∑^{pos[x_i].size()-1}_{j=0}(pos[x_i][j] - (j\ ?\ pos[x_i][j - 1] : -1)) * (n - pos[x_i][j])

代碼

#include <bits/stdc++.h>
#define _for(i, a) for(register int i = 0; i < (a); ++i)
#define _rep(i, a, b) for(register int i = (a); i <= (b); ++i)
#define sc(x) scanf("%d", &x)
using namespace std;
typedef long long LL;
const int maxn = 1000005;

inline int read() {
    int x(0), f(1); char ch(getchar());
    while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
    while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}

struct Prime {
    vector<int> arr;
    int vis[1006];
    void doit(int maxnum) {
        for (int i = 2; i <= maxnum; ++i) {
            if (!vis[i]) arr.push_back(i);
            for (int j = 0; j < arr.size() && arr[j] * i <= maxnum; ++j) {
                vis[arr[j] * i] = 1;
                if (i % arr[j] == 0) break;
            }
        }
    }
};

int n, a[maxn];
Prime pri;
set<int> st;
vector<LL> vv[maxn];

inline void sol() {
    LL ans = 0;
    _for(i, n) {
        int x(a[i]);
        for (int j = 0; j < pri.arr.size() && pri.arr[j] <= x; ++j) {
            int val = pri.arr[j];
            if (x % val == 0) {
                for(; x % val == 0; ) x /= val;
                vv[val].push_back(i);
                st.insert(val);
            }
        }
        if (x > 1) {
            vv[x].push_back(i);
            st.insert(x);
        }
    }
    for (set<int>::iterator it = st.begin(); it != st.end(); ++it) {
        int x(*it);
        _for(i, vv[x].size()) {
            ans += (vv[x][i] - (i ? vv[x][i - 1] : -1)) * (n - vv[x][i]);
        }
    }
    cout << ans << "\n";
}

int main() {
    pri.doit(1000);
    n = read();
    _for(i, n) a[i] = read();
    sol();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章