这道题目给了我们一种解题目的思路就是如果是两个连续求和(两个sigm叠在一起),通过暴力的方式的话需要n*n,一般这种题目我们都是可以将这些题目根据他的特点将这道题目的时间复杂度给降到o(n)*log(n)一般是都是可以这样做的,这种套路遇到了三次了,网络赛的一道题目那个是欧拉函数的前缀和;还有一道是秦皇岛camp的一到题目;还有就是今天的这一道区域赛题目,三道题目都是这样的思路,就是o(n)的求算出第一行的值然后是一行一行的向下运算,在这个过程中不断地维护这一行的值通过上一行的值和我们要删掉的这一个数值的特点;
#include <bits/stdc++.h>
using namespace std;
const int Max = 1e6+10;
typedef long long ll;
bool visited[Max];
ll pri[Max];
ll num,a[Max];
vector <int> mapos[Max], mapri[Max];
void pr(){
for(int i=3;i<=1000001;i++) if(i%2==0) visited[i]=true;
for(int i=2;i<=sqrt(1000001);i++){
for(int j=i*2;j<=1000001;j+=i) visited[j]=true;
}
for(int i=2;i<=1000001;i++) if(!visited[i]) pri[num++]=i;
}
ll du[Max];
set <int>v;
int main(){
int n;
pr();
scanf("%d",&n);
ll sum=0;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
ll ans=a[i];
ll x;
int f;
int k=0;
for(int j=0;j<num;j++){
f=0;
while(ans>1&&ans%pri[j]==0){
ans/=pri[j];
f=1;
x=pri[j];
}
if(f) {
k++;
mapos[x].push_back(i);
mapri[i].push_back(x);
du[x]++;
v.insert(x);
}
if(ans==1) break;
}
a[i]=k;
if(ans>1) v.insert(ans);
sum+=v.size();
}
ll to=sum;
for(int i=1;i<=n-1;i++){
int len=mapri[i].size();
for(int j=0;j<len;j++){
int to=mapri[i][j];
if(du[to]==1){
sum=sum-(n-i);
du[to]--;
}
else if(du[to]>=2){
int pos=-1;
int len1=mapos[to].size();
for(int k=0;k<len1;k++){
int to1=mapos[to][k];
if(to1>i){
pos=to1;
break;
}
}
sum=sum-(pos-i-1);
du[to]--;
}
}
sum-=a[i];
to+=sum;
}
printf("%lld\n",to);
return 0;
}
/************
10
99 62 10 47 53 9 83 33 15 24
*********/
/******************
10
6 7 5 5 4 9 9 1 8 12
*******************/