【20181027T1】洛阳怀【推结论+线性筛+分解质因数+GCD性质】

原题:CF402D

【错解】

唔,先打个表看看

咦,没有坏质数好像就是质因数个数啊

那有坏质数呢?

好像变负数了

推出错误结论:f(x)=x的质因数个数,如果有个坏质数,就乘上-1

然后乱搞,起码花了2个小时

【正解】

用脚趾头想一想都知道怎么可能长这样的?

如果最小质因数是坏的,就去掉-1;否则去掉+1

即好质因数-坏质因数

开个bitset记坏质数,然后先筛一下,计算的时候分解\(\sqrt{1e9}\)质因数就好

对于GCD:因为g[i]%g[i+1]==0,所以后面的操作对前面没有影响

所以预处理前缀GCD,然后从后往前算f,如果<0就除一下

另外:分解质因数应先筛出质数,然后枚举\(\sqrt{X}\)内的质数,一个个分解,最后如果X不为1再把自己加上

复杂度\(O(\sqrt{max(A_i)}+\frac{N\sqrt{N}}{log \sqrt{N}})\)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <bitset>
#define MAXN 2005
#define MAX 1000000
using namespace std;
typedef long long ll;
bitset<1000000005> S;
inline int read()
{
	int ans=0,f=1;
	char c=getchar();
	while (!isdigit(c))
	{
		if (c=='-') f=-1;
		c=getchar();
	}
	while (isdigit(c))
		ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return f*ans;
}
int n,m;
bool np[MAX+5];
int pl[MAX+5],cnt;
void init()
{
	np[1]=1;
	for (int i=2;i<=MAX;i++)
	{
		if (!np[i])
			pl[++cnt]=i;
		for (int j=1;j<=cnt&&i*pl[j]<=MAX;j++)
		{
			np[i*pl[j]]=1;
			if (i%pl[j]==0) break;
		}
	}
}
int calc(int x)
{
	if (x==1) return 0;
	int ans=0;
	bool flag=false;
	for (int i=1;i<=cnt&&pl[i]*pl[i]<=x;i++)
		while (x%pl[i]==0)
		{
			ans+=(S[pl[i]]? -1:1);                          			
			x/=pl[i];
		}
	if(x!=1)ans+=(S[x]? -1:1);
	return ans;
}
int a[MAXN],b[MAXN];
int gcd(int a,int b)
{
	return b? gcd(b,a%b):a;
}
int g[MAXN];
int main()
{
	n=read(),m=read();
	for (int i=1;i<=n;i++) a[i]=read();
	for (int i=1;i<=m;i++) S[read()]=1;
	init();
	for (int i=1;i<=n;i++) g[i]=gcd(g[i-1],a[i]);
	ll ans=0;
	for (int i=1;i<=n;i++) ans+=calc(a[i]);
	int lazy=1;
	for (int i=n;i>=1;i--) 
	{
		g[i]/=lazy;
		int t=calc(g[i]);
		if (t<0)
		{
			ans-=(ll)t*i;
			lazy*=g[i];
		}
	}
	cout<<ans;
	return 0;
}
posted @ 2018-10-27 16:32  lst_mengbier  阅读(231)  评论(0编辑  收藏  举报