计蒜客 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=1∑nj=i∑nfac(k=i∏jak) 的值。其中
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=1∑rj=r∑nfac(k=i∏jai) 这一部分的值进行影响。不难看出,这一部分共包含了
r
r
r 行和
n
−
r
+
1
n-r+1
n−r+1 列,是一个
r
∗
(
n
−
r
+
1
)
r*(n-r+1)
r∗(n−r+1) 的矩形。
对于
a
r
a_r
ar 的每一个质因子,有两种情况。
①:这个质因子是第一次出现。那么此时这个质因子对答案的贡献就为
r
∗
(
n
−
r
+
1
)
r*(n-r+1)
r∗(n−r+1) 。
②:这个质因子并不是第一次出现。如果我们知道这个质因子上一次出现的行位置
p
o
s
pos
pos ,那么这个质因子对答案的贡献就是
(
r
−
p
o
s
)
∗
(
n
−
r
+
1
)
(r-pos)*(n-r+1)
(r−pos)∗(n−r+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。。。还要继续多加努力。