Codeforces Round 868 (Div. 2) 1823C Strongly Composite

一,思路:

        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";
	}
}

        (如有不妥还请大佬在评论区斧正 。

                                                                                                                          ——一只小小萌新)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值