1. 程式人生 > 實用技巧 >ProblemJ.prime game(質因數分解)

ProblemJ.prime game(質因數分解)

題目連結:https://codeforces.com/gym/101981
題意:給你n個數,讓你求[1,n]所有區間的不同質因數個數;
解法:利用試除法分解合數,再分解過程中能求出區間[1,n]中一共有多少個不同素因數,我們假設從[1,n]的所有區間都存在全部不同素因數,等差數列求出區間數,再減去每一個質因數絕對不存在的每個區間;
程式碼如下:


/*************************************************************************
    > File Name: problemA.cpp
# Author: Badwoman
# mail: [email protected]
    > 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個;並且一個區間內的不同質因數個數並不滿足可加性,也就是說我們不能將他們放在一起去解題,這樣會增大我們的解題難度,於是開始思考題目本身,題目本身給了我們一個很好的暗示,既然要求的是關於質因數的,我們為什麼不挨個處理每一個質因數?(因為區間總數我們處理不了)今後要抓住題目所給的條件

,不能夠犯經驗主義的錯誤;