完全没有头绪
听完队友讲的我还是楞了好半天菜慢慢理解.我好菜啊
首先要弄懂题目的意思,转换一下题意就是求每个素因子出现区间的次数.区间长度最短为1.我们分析,第一个数的因子会影响1* n个区间(暂时不考虑重复),第二个数的因子会影响2 * (n-1)个区间,以此类推.因此我们只需要分解每一个数然后加上影响的区间即可.
我们从前往后处理.
可是很容易重复,问题就在于我们如何处理重复的因子.对于位置 i i i的因子 x x x,假设在位置 j j j已经出现过,那么对于 [ 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),即会影响区间的个数.对于后面再出现因子 x x x的时候,因为 j j j对后面的影响已经消去,我们只需要考虑 i i i对后面的影响,所以同样进行操作就可以,因此我们记住因子最后出现的位置然后计算即可.
需要注意分解质因数的时候只需要处理到这个数字的开方就可以,如果这个时候这个数还不为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;
}