ProblemJ.prime game(质因数分解)

题目链接:https://codeforces.com/gym/101981
题意:给你n个数,让你求[1,n]所有区间的不同质因数个数;
解法:利用试除法分解合数,再分解过程中能求出区间[1,n]中一共有多少个不同素因数,我们假设从[1,n]的所有区间都存在全部不同素因数,等差数列求出区间数,再减去每一个质因数绝对不存在的每个区间;
代码如下:


/*************************************************************************
    > File Name: problemA.cpp
# Author: Badwoman
# mail: 1194446133@qq.com
    > Created Time: 2020年11月22日 星期日 13时01分44秒
 ************************************************************************/

#include<set>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<map>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#define ll long long
#define ull unsigned long long
#define pb push_back
#define mp make_pair
using namespace std;
ll n,k;
const ll N = 1e6+10;
bool st[N];ll prime[N],tot,arr[N];
void iniv(){
	ll m = sqrt(N+0.5);st[1] = 1;
	for(ll i=2;i<=1000000;++i){
		if(!st[i]){
			prime[++tot] = i;
			if(i>m)continue;
			for(ll j=i*i;j<=1000000;j+=i)st[j] = 1;
		}
	}
}
bool vis[N];
ll  fac(ll l,ll r){
	ll ans = 0;
	memset(vis,0,sizeof vis);
	for(ll i=l;i<=r;++i){
		ll x = arr[i],now = 1;
		while(x!=1){
			if(x%prime[now]==0){
				if(vis[prime[now]]==false){
					vis[prime[now]] = true;ans++;
				}
				x/=prime[now];
			}
			else now++;
		}
	}
	return ans;
}
ll G[N];
ll pop[N];
void solve(){
	scanf("%lld",&n);
	ll cnt = 0,ans = 0;
	for(ll i=1;i<=n;++i){
		scanf("%lld",&arr[i]);
		ll x = arr[i],now = 1;
		while(x>=prime[now]*prime[now]){
			if(x%prime[now]==0){
				if(G[prime[now]]==0){
					pop[++cnt] = prime[now];
				}
				ll d = i - G[prime[now]] - 1;
				ans -= (d*(d+1))/2;
				G[prime[now]] = i;
				while(x%prime[now]==0)x/=prime[now];
			}
			now++;
		}
		if(x!=1){
            if(G[x]==0)pop[++cnt] = x;
			ll d = i - G[x] - 1;
			ans -= (d*(d+1))/2;
			G[x] = i;
		}
	}
	ll t = (ll)((n*(n+1))/2);
	ans += cnt*t;
	//printf("%lld %lld %lld\n",cnt,t,ans);
	for(ll i=1;i<=cnt;++i){
		ll d = n-G[pop[i]];
		ans -= (d*(d+1))/2;
	}
	printf("%lld\n",ans);
}
int main(){
	iniv();
	solve();
	return 0;
}

我们队的合数分解模板存在些问题,看来要给出来了(欧拉筛)


const int MAXN = 10000;
int prime[MAXN+1];
void getPrime(){
	memset(prime,0,sizeof prime);
	for(int i=2;i<=MAXN;++i){
		if(!prime[i])prime[++prime[0]] = i;
		for(int j=1;j<=prime[0]&&prime[j]<=MAXN/i;++j){
			prime[prime[j]*i]=1;
			if(i%prime[j]==0)break;
		}
	}
}
ll factor[100][2];
int fatCnt;
int getFactors(ll x){
	fatCnt = 0;
	ll tmp = x;
	for(int i=1;prime[i]<=tmp/prime[i];++i){
		factor[fatCnt][1] = 0;
		if(tmp%prime[i]==0){
			factor[fatCnt][0] = prime[i];
			while(tmp%prime[i]==0){
				factor[fatCnt][1]++;
				tmp/=prime[i];
			}
			fatCnt++;
		}
	}
	if(tmp!=1){
		factor[fatCnt][0] = tmp;
		factor[fatCnt][1] = 1;
	}
	return fatCnt;
}

埃氏筛法见题解;需要注意的是,我们进行质因数分解,只需要分解到x>=prime[now]×prime[now];最后如果x!=1那么x必是一个大于sqrt(x)的素数,有且只有一个,并且我们在分解的时候也不需要考虑x/prime[now]他是否是一个素数。
总结:这道题从一开始我们首先想到的是前缀和,因为区间个数是n*(n+1)/2个;并且一个区间内的不同质因数个数并不满足可加性,也就是说我们不能将他们放在一起去解题,这样会增大我们的解题难度,于是开始思考题目本身,题目本身给了我们一个很好的暗示,既然要求的是关于质因数的,我们为什么不挨个处理每一个质因数?(因为区间总数我们处理不了)今后要抓住题目所给的条件,不能够犯经验主义的错误;

posted @ 2020-11-24 11:21  xiaodangao  阅读(248)  评论(0)    收藏  举报