1. 程式人生 > >【數論】洛谷P1414又是畢業季II

【數論】洛谷P1414又是畢業季II

can pre 高考 for mes 開始 輸入 們的 cnblogs

題目背景

“叮鈴鈴鈴”,隨著高考最後一科結考鈴聲的敲響,三年青春時光頓時凝固於此刻。畢業的欣喜怎敵那離別的不舍,憧憬著未來仍毋忘逝去的歌。1000多個日夜的歡笑和淚水,全凝聚在畢業晚會上,相信,這一定是一生最難忘的時刻!

題目描述

彩排了一次,老師不太滿意。當然啦,取每位同學的號數來找最大公約數顯然不太合理。於是老師給每位同學評了一個能力值。於是現在問題變為,從n個學生中挑出k個人使得他們的默契程度(即能力值的最大公約數)最大。但因為節目太多了,而且每個節目需要的人數又不知道。老師想要知道所有情況下能達到的最大默契程度是多少。這下子更麻煩了,還是交給你吧~

PS:一個數的最大公約數即本身。

輸入輸出格式

輸入格式:

第一行一個正整數n。

第二行為n個空格隔開的正整數,表示每個學生的能力值。

輸出格式:

總共n行,第i行為k=i情況下的最大默契程度。

輸入輸出樣例

輸入樣例#1:
4
1 2 3 4
輸出樣例#1:
4
2
1
1

說明

【題目來源】

lzn原創

【數據範圍】

記輸入數據中能力值的最大值為inf。

對於20%的數據,n<=5,inf<=1000

對於另30%的數據,n<=100,inf<=10

對於100%的數據,n<=10000,inf<=1e6

題解

一開始很容易想到枚舉n個數取k個的所有組合,然後分別用輾轉相除法求最大公約數,但是復雜度明顯不符合要求,於是必須換一種思路。

我們想到k個數的公約數含義就是這k個數均含有某個因數

如果我們把所有數的因數全部求出來,發現有k個數均含有某個因數,那麽這個數必然是這k個數的公約數

其中找出最大的就是它們的最大公約數。但是要如何高效的做到這點呢?

考慮到對於k=1,2……,n都要求出,我們可以這麽做:

  • 1、 求出每個因數出現的次數。

  • 2、 對於每個次數記錄最大的因數。

  • 3、記錄能力最大值之後用while語句將其不斷減小(因為k=1時顯然最大公約數為最大能力值,之後的公約數顯然小於等於前一個數)

算法復雜度o(n*sqrt(inf))。

代碼如下:

#include<cstdio>
#include
<iostream> #include<cmath> using namespace std; int n,ma,a[10010],b[1000010]; int main() { scanf("%d",&n); for(int i=1;i<=n;++i) { scanf("%d",&a[i]); ma=max(ma,a[i]); int k=sqrt(a[i]); for(int j=1;j<=k;++j) if(a[i]%j==0) { b[j]++; if(j*j!=a[i])b[a[i]/j]++; } } for(int i=1;i<=n;++i) { while(b[ma]<i)ma--; printf("%d\n",ma); } }

【數論】洛谷P1414又是畢業季II