完全没有头绪
听完队友讲的我还是楞了好半天菜慢慢理解.我好菜啊
首先要弄懂题目的意思,转换一下题意就是求每个素因子出现区间的次数.区间长度最短为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;
}