家喻戶曉的中藥店 (題解及一些素數打表方法)
阿新 • • 發佈:2018-12-22
問題描述
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
看到這個題的第一反應就是要打表,這裡說一下幾種素數打表的方法
- 普通方法
時間複雜度為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;
}
}
}
- 普通方法改進——迴圈到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;
}
}
}
- 普通篩表——埃拉託斯特尼篩法
所使用的原理是從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;
}
}
}
- 線性篩表——尤拉篩表
時間複雜度降低到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;
}