一,思路:
1.首先我们要清楚大于1的所有正整数都可以是素数相乘得到;
2.最简强合数有两种情况:(两个相同的素数相乘)和(三个不同的素数相乘);
3.k的最大值 换句话说就是 最简强合数的个数;
(如:
案例五:2
25 30;
25*30=5*5*5*2*3;
两个5可组成一个最简强合数,一个5一个2和一个3可组成一个最简强合数;
也就是25*30=(5*5)*(2*3*5);k=2;
案例八:20
12 15 2 2 2 2 2 3 3 3 17 21 21 21 30 6 6 33 31 39;
令sum为数组a的所有数的乘积;
sum=(2^10)*(3^13)*(5^2)*(7^3)*11*13*17*31;
所以最简强合数有15组:
(2*2)^5,(3*3)^6,(5*5)^1,(7*7)^1,(3*7*11)^1,(13*17*31)
故k=5+6+1+1+1+1=15;
)
二,实现:
1:用欧拉筛筛出所有素数到ans数组中,以st数组为标记数组同时计数(令st数组的下标为素数时初始值为0,其下标为合数时初始值为-1);
2:输入a数组的数时,将每个数拆解成多个素数m,每出现一个素数m,就让st[m]++,以此计数;
3:最后寻找每个素数的个数,像上述案例一样计数;(代码中ans1为(a*a)型最简强合数个数,ans2为(a*b*c)型最简强合数个数)
(代码中a数组就是上述的ans数组)
#include<iostream>
using namespace std;
#define int long long
int a[10000007];
int st[10000007]={0};
int op=0;
int N=1e7;
void oula ()
{
for(int i=2;i<=N;i++)
{
if(!st[i]) a[++op]=i;
for(int j=1;j<=op&&a[j]*i<=N;j++)
{
st[a[j]*i]=-1;
if(i%a[j]==0) break;
}
}
}
signed main()
{
ios_base::sync_with_stdio();
oula();
int t;
cin>>t;
while(t--)
{
for(int i=1;i<=op;i++)
{
st[a[i]]=0;
}
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
int m;
cin>>m;
int id=1;
if(st[m]==-1)
{
while(m!=1&&id<=op&&a[id]*a[id]<=m)
{
while(m%a[id]==0)
{
st[a[id]]++;
m=m/a[id];
}
id++;
}
if(m!=1)
{
st[m]++;
}
}
else
{
st[m]++;
}
}
int ans1=0,ans2=0;
for(int i=1;i<=1e7;i++)
{
if(st[a[i]]>=2)
{
ans1=ans1+st[a[i]]/2;
if(st[a[i]]%2)
{
st[a[i]]=1;
}
else
st[a[i]]=0;
}
if(st[a[i]]==1)
{
ans2++;
}
}
cout<<ans1+ans2/3<<"\n";
}
}
你以为这就完了?
还有优化的余地,这样案例是都过了,但每次循环记录ans1和ans2时都要跑1e7次未免太浪费时间了,交了也只有T的份;
三,优化:
我们可以再定义 一个数组pr来储存出现的素数 和 一个整数k,k用来记录出现了多少种素数;如此我们每循环一遍 要跑1e7次来记录ans1和ans2 变成了 仅仅需要跑k次;
(ac代码如下)
#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[10000007];
int st[10000007]={0};
int op=0;
const int N=1e7;
void oula ()
{
for(int i=2;i<=N;i++)
{
if(!st[i]) a[++op]=i;
for(int j=1;j<=op&&a[j]*i<=N;j++)
{
st[a[j]*i]=-1;
if(i%a[j]==0) break;
}
}
}
int pr[N],k;
signed main()
{
std::ios::sync_with_stdio(false);
oula();
int t;
cin>>t;
while(t--)
{
for(int i=1;i<=k;i++)
{
st[pr[i]]=0;
}
k=0;
int n;
cin>>n;
for(int j=1;j<=n;j++)
{
int m;
cin>>m;
int i=1;
while(a[i]*a[i]<=m&&i<=op&&m!=1)
{
while(m%a[i]==0)
{
if(st[a[i]]==0) pr[++k]=a[i];
st[a[i]]++;
m/=a[i];
}
i++;
}
if(m!=1)
{
if(st[m]==0) pr[++k]=m;
st[m]++;
}
}
int ans1=0,ans2=0;
for(int i=1;i<=k;i++)
{
if(st[pr[i]]>=2)
{
ans1=ans1+st[pr[i]]/2;
if(st[pr[i]]%2)
{
st[pr[i]]=1;
}
else
st[pr[i]]=0;
}
if(st[pr[i]]==1)
{
ans2++;
}
}
cout<<ans1+ans2/3<<"\n";
}
}
(如有不妥还请大佬在评论区斧正 。
——一只小小萌新)