家喻户晓的中药店 (题解及一些素数的方法)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Nicht_sehen/article/details/84179221

问题描述

long_xiao和const_hhh是一对恩爱的夫妻。

他们在京城经营着一家中药店,夫妻二人医术精湛、古道热肠,虽然年过花甲,身体依然硬朗。更重要的是,他们的思维仍然十分活跃,不仅了解大家的要求,还能给他们许多惊喜。

除了治病救人,他们的中药配方还有舒筋活络,排毒养颜的功效。正因为如此,中药店门庭若市,甚至有人不远千里,慕名而来。

药店里药材种类繁多,组成的配方也就非常多。为了提高服务质量,店里的伙计灰来灰去将药材和配方进行编号,灰来灰去可以通过配方的编号快速找到所需药材的编号。

一天,店里的伙计灰来灰去提议可以借此机会来向大家普及一下数学知识,夫妻二人表示赞成,决定每周一在店门口的公告栏中发布新的知识点。

这周一他们提供了一个简单但是有趣的知识点:

“素数:一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做素数“。

到了周末,灰来灰去为了检验大家对知识点的掌握情况,使得今天的配方都由三种药材组成,所需的三种药材的编号都为素数,且加起来等于配方的编号。因为会有多种情况出现,灰来灰去使得三个素数的乘积最大。

现在,药店会给你开出一剂配方,编号为n。如果你能把他拆成3个素数的和或者告诉灰来灰去无法拆成3个素数的和,那么灰来灰去就可以快速找到药材,并免费赠送你一副他们的镇店配方。

输入描述

输入第一行包含一个正整数T,代表有T次配方的询问。

对于每组数据,输入包含一个正整数n(1<=n<=10000),代表配方的编号。

输出描述

对于每组数据,如果n不能写成三个素数的和,输出-1。
否则在一行从小到大输出三个素数以及最大乘积。

样例输入

2
20
3

样例输出

2 7 11 154
-1
看到这个题的第一反应就是要打表,这里说一下几种素数打表的方法

  1. 普通方法
    时间复杂度为O(n^2)
void prime(int n)
{
	for (int i = 2; i < n; i++)
	{
		int j;
		for (j = 2; j <= i; j++)  
		{
			if (i%j==0) break;
		}
	}
}
  1. 普通方法改进——循环到sqrt(n)
    时间复杂度为O(n*sqrt(n))
void prime(int n)
{
	for (int i = 2; i < n; ++i)
	{
		int j;
		for (j = 2; j <= sqrt(i); ++j)  
		{
			if (i%j==0) break;
		}
	}
}

  1. 普通筛表——埃拉托斯特尼筛法
    所使用的原理是从2开始,将每个素数的各个倍数,标记成合数。一个素数的各个倍数,是一个差为此素数本身的等差数列。此为这个筛法和试除法不同的关键之处,后者是以素数来测试每个待测数能否被整除。时间复杂度为O(n log log n)
void isprime(int n, int prime[]) 
{
    int i;
    for(i = 0; i <= n; i++) 
        prime[i] = i;
    int j;
    for(j = 2; j < sqrt(n); j++)
     {
        int k;
        for(k = j + 1; k <= n; k++)
         {
            if(prime[k] != 0 && prime[k] % j == 0) 
            	prime[k] = 0;
        }
    }
} 
  1. 线性筛表——欧拉筛表
    时间复杂度降低到O(n)
void isprime()
{
   memset(visit, true, sizeof(visit));
   int num = 0;
   for (int i = 2; i <= n; ++i)
   {
       if (visit[i] == true)
       {
           num++;
           prime[num] = i;
       }
       for (int j = 1; ((j <= num) && (i * prime[j] <= n));  ++j)
       {
           visit[i * prime[j]] = false;
           if (i % prime[j] == 0) break; 
       }
           
   }
}

本题代码:

#include<stdio.h>
#include<math.h>
#include<string.h>
#define min(a,b)(a<b?a:b)
#define max(a,b)(a>b?a:b)

int prime[10000];
int num;
bool visit[10000];


void pr()
{
    memset(visit, true, sizeof(visit));
    num = 0;
    for (int i = 2; i <= 10000; ++i)
    {
        if (visit[i] == true)
        {
            num++;
            prime[num] = i;
        }
        for (int j = 1; ((j <= num) && (i * prime[j] <= 10000));  ++j)
        {
            visit[i * prime[j]] = false;
            if (i % prime[j] == 0) break; 
        }
            
    }
}

int main()
{
	pr();
	int t,n;
	scanf("%d",&t);
	while(t--)
	{	
		scanf("%d",&n);
		long long int Max=-1,m;
		int x,y,z,k;
		for(int i=0;i<num;i++)
		{
			for(int j = 0 ; j<num ; j++)
			{
				int k = n-prime[i]-prime[j];
				if(k >=0 && visit[k])
				{
					m=(long long int)prime[i]*prime[j]*k;
					if((m > Max)&&m)
					{	
						Max = m;
						x = min(prime[i] , min(prime[j] , k));
						z = max(prime[i] , max(prime[j] , k));
						y = n-x-z;
					}		
				}
			} 
		}
		if(Max == -1) 
			 printf("-1\n");
		else	
			printf("%d %d %d %lld\n",x,y,z,Max);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Nicht_sehen/article/details/84179221