題目連接:http://codeforces.com/gym/101981/attachmentsc++
題意:spa
令 $mul(l,r) = \prod_{i=l}^{r}a_i$,且 $fac(l,r)$ 表明 $mul(l,r)$ 的不一樣素因子個數。求 $\sum_{i=1}^{n}\sum_{j=i}^{n}fac(i,j)$。code
Input
The first line contains one integer n (1 \le n \le 10^6) — the length of the sequence.
The second line contains n integers ai (1 \le i \le n, 1 \le a_i \le 10^6) — the sequence.blog
Output
Print the answer to the equation.get
Examples
standard input
10
99 62 10 47 53 9 83 33 15 24input
standard output
248it
standard input
10
6 7 5 5 4 9 9 1 8 12io
standard outputclass
134im
題解:
考慮每一個質因子對於總體答案的貢獻。
拿第二組樣例算一算就不難發現:第 $p$ 個位置上的數,其包含的任意一個素因子,它本來應當產生的貢獻有 $(n-p+1) \cdot p$,
可是考慮到若其前面出現過同樣的素數,那麼應當減去一些重複計算的區間。假設它前面的和它同樣的素數,最後一次出如今 $q$ 位置,那麼就應當減去 $(n-p+1) \cdot q$,即 $a[p]$ 包含的任意一個質因子其產生的貢獻爲 $(n-p+1) \cdot p - (n-p+1) \cdot q = (n-p+1) \cdot (p - q)$。
不妨用 $pos[i][k]$ 來存儲每一個素因子的 「$p$」,$pos[i][k-1]$ 存儲每一個素因子的 「$q$」。換句話說,$pos[i][k]$ 表明某個素因子 $i$ 在 $a[1 \sim n]$ 中第 $k$ 次「出現」的位置是 $pos[i][k]$;特別地,令 $pos[i][0]=0$。那麼對於任意素因子 $i$,它對答案的貢獻是 $(n-pos[i][k]+1) \cdot (pos[i][k]-pos[i][k-1])$。
咱們能夠對 $a[1 \sim n]$ 分解質因數,而後更新相應的 $pos[i][k]$。
AC代碼:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1e6+5; int n,a[maxn]; vector<int> pos[maxn]; void dec(int p) { int n=a[p]; for(int i=2;i*i<=n;i++) { if(n%i==0) { pos[i].push_back(p); while(n%i==0) n/=i; } } if(n>1) pos[n].push_back(p); } int main() { for(int i=2;i<maxn;i++) pos[i].push_back(0); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); dec(i); } ll ans=0; for(int i=2;i<maxn;i++) { for(int k=1;k<pos[i].size();k++) ans+=(ll)(n-pos[i][k]+1)*(pos[i][k]-pos[i][k-1]); } cout<<ans<<endl; }
分解質因數板子:
vector<int> dec(int n) { vector<int> p; for(int i=2;i*i<=n;i++) { if(n%i==0) { p.push_back(i); while(n%i==0) n/=i; } } if(n>1) p.push_back(n); return p; }
交了一發,大概700ms多點過了,那咱們可否加快一下速度呢?
咱們能夠先用線性篩篩出 $[1,1e6]$ 的素數,而後再作分解質因數:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1e6+5; int n,a[maxn]; vector<int> pos[maxn]; const int MAX=1e6; int tot,prime[MAX/10]; bool isPrime[MAX+3]; void Screen() //歐拉篩 { tot=0; memset(isPrime,1,sizeof(isPrime)); isPrime[0]=isPrime[1]=0; for(int i=2;i<=MAX;i++) { if(isPrime[i]) prime[tot++]=i; for(int j=0;j<tot;j++) { if(i*prime[j]>MAX) break; isPrime[i*prime[j]]=0; if(i%prime[j]==0) break; } } } void dec(int p) { int n=a[p]; for(int i=0;i<tot && prime[i]*prime[i]<=n;i++) { if(n%prime[i]==0) { pos[prime[i]].push_back(p); while(n%prime[i]==0) n/=prime[i]; } } if(n>1) pos[n].push_back(p); } int main() { Screen(); for(int i=0;i<tot;i++) pos[prime[i]].push_back(0); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); dec(i); } ll ans=0; for(int i=0;i<tot;i++) { for(int k=1;k<pos[prime[i]].size();k++) ans+=(ll)(n-pos[prime[i]][k]+1)*(pos[prime[i]][k]-pos[prime[i]][k-1]); } printf("%I64d\n",ans); }
跑了大概400ms,仍是快了很多的。