【CF402D】Upgrading Array(素数+质因数+gcd+贪心)

不难发现 题目中给出的f函数 其实就是一个数分解质因数后好素数和坏素数的个数之差

也就是说 数x带来的贡献 与x的质因数的种类有关系 又联想到gcd[1~x]一定是这个数的因子 也就是说一个数的贡献可以表示成:f(gcd[1~x])+f(....)

容易想到贪心做法:我们从后往前枚举 如果当前gcd前缀带来的贡献<0 就除一下

另外有几个小细节我平时没有注意到的:
1.线性筛素数 其实枚举范围只需要到区间根号范围就行 如果要用到特别大的那几个素数只需特判就行(46行)
2.map和bitset屌爆了

#include<bits/stdc++.h> 
#define N 2000005
#define MAX 5000000
#define int long long
using namespace std;
template<class T>
inline void read(T &x)
{
	x=0;
	static char ch=getchar();
	while(ch<'0'||ch>'9')	ch=getchar();
	while(ch>='0'&&ch<='9')	x=x*10+ch-'0',ch=getchar();
}
int n,m,a[N],gcd[N];
int prime[MAX+5],cnt,isprime[MAX+5];
bitset<1000000005> bad;
inline int calcgcd(int a,int b)
{
    return b? calcgcd(b,a%b):a;
}
void GetPrime()
{
	isprime[0]=isprime[1]=1;
	for(register int i=2;i<=MAX;i++)
	{
		if(!isprime[i])	prime[++cnt]=i;
		for(register int j=1;j<=cnt&&i*prime[j]<=MAX;j++)
		{
			isprime[i*prime[j]]=1;
			if(i%prime[j]==0)	break;
		}
	}
}
inline int calc(int x)
{
	if(x==1)	return 0;
	int sum=0;
	for(int i=1;i<=cnt&&prime[i]*prime[i]<=x;i++)
	{
		while(x%prime[i]==0)
		{
			sum+=(bad[prime[i]]?-1:1);
			x/=prime[i];
		}
	}
	if(x!=1)	sum+=(bad[x]?-1:1);
	return sum; 
}
main()
{
	read(n); read(m); 
	for(int i=1;i<=n;i++)	read(a[i]),gcd[i]=calcgcd(a[i],gcd[i-1]);
	GetPrime();
	for(int i=1,x;i<=m;i++)	read(x),bad[x]=true;
	int ans=0,tag=1;
	for(int i=1;i<=n;i++)	ans+=calc(a[i]);
	for(int i=n;i>=1;i--)
	{
		gcd[i]/=tag;
		int tmp=calc(gcd[i]);
		if(tmp<0)
		{
			ans-=tmp*i;
			tag*=gcd[i];
		}
	}
	cout<<ans<<endl;
	return 0;
}
posted @ 2018-10-27 21:49  Patrickpwq  阅读(147)  评论(0编辑  收藏  举报