J. Prime Game(The 2018 ACM-ICPC Asia Nanjing)(思维+线筛)
Time limit: 2000 ms
Memory limit: 1048576 kB
judge:vjudge
Description
Given a suqence of n n n integers a i a_i ai .
Let m u l ( l , r ) mul(l, r) mul(l,r) = ∏ i = l r a i ∏^r_{i=l} a_i ∏i=lrai and f a c ( l , r ) fac(l, r) fac(l,r) be the number of distinct prime factors of m u l ( l , r ) mul(l, r) mul(l,r).
Please calculate ∑ i = 1 n ∑ j = i n f a c ( i , j ) ∑^n_{i=1}∑^n_{j=i}fac(i, j) ∑i=1n∑j=infac(i,j)
Input
The first line contains one integer n ( 1 ≤ n ≤ 1 0 6 ) n (1 ≤ n ≤ 10^6) n(1≤n≤106) — the length of the sequence.
The second line contains n n n integers a i ( 1 ≤ i ≤ n , 1 ≤ a i ≤ 1 0 6 ) a_i (1 ≤ i ≤ n, 1 ≤ a_i ≤ 10^6) ai(1≤i≤n,1≤ai≤106) — 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
题意
给你两个函数:
m u l ( l , r ) = ∏ i = l r a i mul(l, r)=∏^r_{i=l} a_i mul(l,r)=i=l∏rai
f a c ( l , r ) = m u l ( l , r ) 的 素 因 子 的 个 数 fac(l,r)=mul(l,r)的素因子的个数 fac(l,r)=mul(l,r)的素因子的个数
让你求解:
∑ i = 1 n ∑ j = i n f a c ( i , j ) ∑^n_{i=1}∑^n_{j=i}fac(i, j) i=1∑nj=i∑nfac(i,j)
题意
刚看到这题的时候吓坏了:我的天、素数、1e6、还累乘、求和后再求和……
但是仔细一想好像有点变化。
把每个数字看成一系列素数的集合,集合里的素数都是它的因子,那么两个数相乘之后他们的素因子的集合就相当于把原来两个数字对应的素数因子的集合合并到了一起。
我们不要把序列里的数字看成整体,换个角度:把每个素数对答案做出的贡献看成一个整体,我们枚举所有出现过的素数,分别计算贡献,最后求和即可。
那么每个素数的贡献就是包含它的区间的个数,如果区间内包含多个相同的素数,贡献不叠加计算,算作一个区间。如图:
假设序列所有的素因子一共有k个,用 p o s [ x ] [ i ] pos[x][i] pos[x][i] 表示素数 x x x 出现的第 i i i 个位置 ( 0 ≤ i ) (0≤i) (0≤i) 。那么2出现的位置有这些:0,4,8,9.
2对答案做出的贡献:43
根据这张图相信不难看出规律,,那么答案就是:
a n s = ∑ i = 0 k − 1 x i ∑ j = 0 p o s [ x i ] . s i z e ( ) − 1 ( p o s [ x i ] [ j ] − ( j ? p o s [ x i ] [ j − 1 ] : − 1 ) ) ∗ ( n − p o s [ x i ] [ 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]) ans=i=0∑k−1xij=0∑pos[xi].size()−1(pos[xi][j]−(j ? pos[xi][j−1]:−1))∗(n−pos[xi][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;
}