https://blog.csdn.net/m0_37624640/article/details/83276324
博主代码写的清楚明白
把每个数分解素因子,分别在对应的素因子vector内放入该数的位置
那么,由于一个数不同的素因子不会超过8个(2*3*5*7*11*13*17*19=9 699 690)
那么最后所有vector里的位置的个数总和也不会超过8e6,遍历即可
一个素因子在pos位置,可能产生的贡献在
左端点在[1,pos]取,右端点在[pos,n]取,
可与它相同的素因子再次出现的时候,不妨出现在next位置
右端点[next,n]取没问题,
左端点应该在[pos+1,next]取,而不是[1,next]取,
避免和上一个位置计算重复的部分
故一个素因子的贡献是
第一个出现的位置pos*(n-pos+1)
后面出现的位置(next-pos)*(n-next+1)
求和即可
往这个有位置的素因子里面先塞个0
所有操作就都统一成(next-pos)*(n-next+1)了
这题卡时间卡得很紧
要求欧拉筛(其实素数筛也能过)+枚举不超过平方素因子写得足够标准
开始用遍历筛出来的所有素数的方法去筛果不其然T了,
后来想想1e6以内的素数有约5e4个,而1e3以内的质数只有168个
多乘了个300的系数不T才怪呢……
分解素因子的时候由于出现了就除掉,实际访问的质数也不会到168
估计cal上限那也就不到100叭,乘一下1e6就搞过去了
以后代码要写的规范呐,别整天debug这些没用的...
#include
#include
#include
#include
#include
const int maxn=1e6+10;
typedef long long ll;
using namespace std;
int n;
ll prime[maxn],cnt,ans;
bool ok[maxn];
vectorpos[maxn];//放的是各素因数出现的位置
void init()
{
for(ll i=2;i<=maxn;++i)
{
if(!ok[i])
{
prime[cnt++]=i;
pos[i].push_back(0);//统一操作
}
for(ll j=0;jmaxn)break;
ok[prime[j]*i]=1;
if(i%prime[j]==0)break;
}
}
}
void cal(int a,ll x)
{
for(int i=0;ix)break;//1000以内的质数的复杂度 168
if(x%prime[i]==0)
{
pos[prime[i]].push_back(a);
while(x%prime[i]==0)x/=prime[i];
}
}
if(x>1)pos[x].push_back(a);//用平方写 有效降复杂度
}
int main()
{
init();
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
ll x;
scanf("%lld",&x);
cal(i,x);
}
for(int i=0;i