完全沒有頭緒
聽完隊友講的我還是楞了好半天菜慢慢理解.我好菜啊
首先要弄懂題目的意思,轉換一下題意就是求每個素因子出現區間的次數.區間長度最短為1.我們分析,第一個數的因子會影響1* n個區間(暫時不考慮重復),第二個數的因子會影響2 * (n-1)個區間,以此類推.因此我們只需要分解每一個數然后加上影響的區間即可.
我們從前往后處理.
可是很容易重復,問題就在于我們如何處理重復的因子.對于位置iii的因子xxx,假設在位置jjj已經出現過,那么對于[j,i?1][j,i-1][j,i?1]的區間是沒有影響的,可是對于以[1,j][1,j][1,j]開頭的區間和以[i,n][i,n][i,n]結尾的區間這個因子就會重復計數,因此為了消去重復,我們給答案減去j?(n?i+1)j*(n-i+1)j?(n?i+1),即會影響區間的個數.對于后面再出現因子xxx的時候,因為jjj對后面的影響已經消去,我們只需要考慮iii對后面的影響,所以同樣進行操作就可以,因此我們記住因子最后出現的位置然后計算即可.
需要注意分解質因數的時候只需要處理到這個數字的開方就可以,如果這個時候這個數還不為1就說明剩下的一定是一個質數就不要進行處理了,否則會超時.
記得開long long ,而且要注意中間會爆long long ,所以在更新ans的時候要小心.
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<climits>
#include<cctype>
#include<queue>
#include<set>
#include<cmath>using namespace std;typedef long long ll;
const int INF=0x3f3f3f3f;
const int MAXN=1e6+5;
const int MAXM=1e6+5;int check[MAXM];
int prime[MAXM];
int vis[MAXM];
int tot=0;
int n,x;
ll ans;void creat_prime()
{for(int i=2;i<MAXN;i++){if(!check[i]) prime[tot++]=i;for(int j=0;j<tot && prime[j]*i<MAXN;j++){check[prime[j]*i]=true;if(i%prime[j]==0) break;}}
}void deal(int x,int idx)
{int t=sqrt(x)+1;for(int i=0;i<tot && prime[i]<=t;i++){if(x%prime[i]==0){ans+=(ll)idx*(n-idx+1);if(vis[prime[i]]==0) vis[prime[i]]=idx;else{ans-=(ll)vis[prime[i]]*(n-idx+1);vis[prime[i]]=idx;}while(x%prime[i]==0){x/=prime[i];}}if(x==1) break;}if(x>1){ans+=(ll)idx*(n-idx+1);if(vis[x]==0) vis[x]=idx;else{ans-=(ll)vis[x]*(n-idx+1);vis[x]=idx;}}
}int main()
{creat_prime();scanf("%d",&n);ans=0;for(int i=1;i<=n;i++){scanf("%d",&x);deal(x,i);}printf("%lld\n",ans);return 0;
}