题目链接: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个;并且一个区间内的不同质因数个数并不满足可加性,也就是说我们不能将他们放在一起去解题,这样会增大我们的解题难度,于是开始思考题目本身,题目本身给了我们一个很好的暗示,既然要求的是关于质因数的,我们为什么不挨个处理每一个质因数?(因为区间总数我们处理不了)今后要抓住题目所给的条件,不能够犯经验主义的错误;