ACM-ICPC 2018南京现场赛 J-Prime Game(枚举素因子贡献+欧拉筛)

题目

ACM-ICPC 2018南京现场赛 J-Prime Game(枚举素因子贡献+欧拉筛)_第1张图片

思路来源

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

 

你可能感兴趣的:(数论)