1. 程式人生 > >【題解】桐桐的猜想

【題解】桐桐的猜想

title alt 時間復雜度 prev tro 兩個 goto space -o

題目描述

今天,桐桐在復習素數的知識時,發現了有趣的現象,例如4=2+2,5=2+3,6=3+3,7=2+5等等,桐桐列舉了很多數,都是這樣,所以她大膽地得出了一個結論:任何一個不小於4的數都能表示成兩個質數的和。你能找出一些反例,證明桐桐的結論是錯誤的嗎?

輸入輸出格式

輸入格式

兩行,第一行為一個整數n(1≤n≤50);接下來有n行,每行包含一個整數m。3m106(3≤m≤106)

輸出格式

共n行,每行對應於每一個m,如果m不能表示成兩個質數的和,則輸出“NO WAY!”;否則輸出一種方案。如果有多種可行方案,輸出兩個質數的差最大的那一種。

輸入輸出樣例

輸入樣例

2

10

11

輸出樣例

10=3+7

NO WAY!

題解

一般人看到這題都是直接用篩法,事實上這個方法也可以。

技術分享圖片
#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

int m, n[55], maxn;
int p[1000005];
int a[100005], cnt;

int main()
{
    scanf(
"%d", &m); for(register int i = 1; i <= m; ++i) { scanf("%d", n + i); if(n[i] > maxn) maxn = n[i]; } for(register int i = 2; i <= maxn; ++i) { if(!p[i]) a[++cnt] = i; for(register int j = 1; i * a[j] <= maxn; ++j) { p[i
* a[j]] = 1; if(!(i % a[j])) break; } } int op; for(register int i = 1; i <= m; ++i) { op = 0; for(register int j = 1; a[j] <= n[i] - a[j]; ++j) { if(!p[n[i] - a[j]]) { printf("%d=%d+%d\n", n[i], a[j], n[i] - a[j]); op = 1; break; } } if(!op) printf("NO WAY!\n"); } return 0; }
參考程序1

但實際上這題,其實當m為偶數時間復雜度時是強哥德巴赫猜想,當m為奇數時,應該等於奇數加偶數,而偶數質數只有2,所以就能轉換成當m為奇數時,判斷m-2是否為質數

技術分享圖片
#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

int m, n[55], maxn;
int p[1000005];
int a[100005], cnt;

int main()
{
    scanf("%d", &m);
    for(register int i = 1; i <= m; ++i)
    {
        scanf("%d", n + i);
        if(n[i] > maxn) maxn = n[i];
    }
    int srmaxn = sqrt(maxn);
    a[++cnt] = 2;
    for(register int i = 4; i <= maxn; i += 2)
    {
        p[i] = 1;
    }
    for(register int i = 3; i <= srmaxn; i += 2)
    {
        if(p[i]) continue;
        a[++cnt] = i;
        for(register int j = i + i; j <= maxn; j += i)
        {
            p[j] = 1;
        }
    }
    for(register int i = 1; i <= m; ++i)
    {
        if(n[i] & 1)
        {
            if(p[n[i] - 2]) printf("NO WAY!\n");
            else printf("%d=2+%d\n", n[i], n[i] - 2);
        }
        else
        {
            // 哥德巴赫猜想
            for(register int j = 1; ; ++j)
            {
                if(!p[n[i] - a[j]])
                {
                    printf("%d=%d+%d\n", n[i], a[j], n[i] - a[j]);
                    break;
                }
            }
        }
    }
    return 0;
}
參考程序2

到現在之後,其實這個程序還有優化的地方。

題目中給的n很小,我們可以把篩法縮減,然後後面暴力判斷質數即可,這樣就可以做到0ms了。所以合理分析時間復雜度還是很重要的。

技術分享圖片
#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

int m, n[55], maxn;
int p[1000005];
int a[100005], cnt;

int main()
{
    scanf("%d", &m);
    for(register int i = 1; i <= m; ++i)
    {
        scanf("%d", n + i);
        if(n[i] > maxn) maxn = n[i];
    }
    int srmaxn = sqrt(maxn);
    a[++cnt] = 2;
    for(register int i = 4; i <= srmaxn; i += 2)
    {
        p[i] = 1;
    }
    for(register int i = 3; i <= srmaxn; i += 2)
    {
        if(p[i]) continue;
        a[++cnt] = i;
        for(register int j = i + i; j <= srmaxn; j += i)
        {
            p[j] = 1;
        }
    }
    int op;
    for(register int i = 1; i <= m; ++i)
    {
        if(n[i] & 1)
        {
            op = 0;
            for(register int j = 1; a[j] < n[i] - 2 && j <= cnt; ++j)
            {
                if((n[i] - 2) % a[j]) continue;
                printf("NO WAY!\n");
                op = 1;
                break;
            }
            if(!op) printf("%d=2+%d\n", n[i], n[i] - 2);
        }
        else
        {
            // 哥德巴赫猜想 
            for(register int j = 1; a[j] <= n[i] - a[j]; ++j)
            {
                for(register int k = 1; a[k] < n[i] - a[j] && k <= cnt; ++k)
                { 
                    if((n[i] - a[j]) % a[k]) continue;
                    goto NO_WAY;
                }
                printf("%d=%d+%d\n", n[i], a[j], n[i] - a[j]);
                break;
                NO_WAY:;
            }
        }
    }
    return 0;
}
參考程序3

【題解】桐桐的猜想