cf1208G Polygons 歐拉函數

連接

cf
給你兩個正整數\(n\)\(k\),詢問在一個圓上你最少須要幾個點構才能造出\(k\)個邊數小於等於\(n\)的正多邊形c++

思路

深受迫害,因此寫的詳細一點,不會請留言。spa

性質1

考慮加進一個\(x\)邊形。那麼他的因子\(d\)必定在他以前加進來了.
由於\(d\)能夠徹底由\(x\)的點表現出來。
若是沒加\(d\),那麼加\(d\)顯然比加\(x\)優秀(顯然)。code

性質2

兩個圖形,讓他們儘可能多的重合些點是好的。
那兩個圖形能重合多少點呢?答案顯然是固定的。
兩個圖形讓他們一個點重合,便可獲得最好的。
由於是正多邊形,因此隨便重合一個點,重合的狀況都是同樣的。
即最優的答案。
因此咱們加入的\(k\)個正多邊形都重合到一個點上,設這個點爲\(0\)點。ci

聯繫起來

\(x\)在圓上,假設他的點爲\(\frac{0}{x},\frac{1}{x}……\frac{x-1}{x}\)
\(part2\)能夠知道,0這個點上每一個圖形都會通過。
\(part1\)能夠知道\(x\)的點上,他的因子在以前就會加入,因此他的因子及其倍數都是原先就有的(被覆蓋過)。
這個過程就是相似於暴力篩\(phi\)的過程,因此剩下的就是與他互質的數。
因此一個正\(x\)邊形的貢獻就是\(phi(x)\).
找出\(k\)個最小的\(phi\)就好了
其實這個題就是俄羅斯數學競賽的題目....我同桌給我講過相似的證實,忘記了(菜)。get

代碼

由於1,2不是正x邊形,因此不能選爲k變形數學

#include <bits/stdc++.h>
using namespace std;
const int _=1e6+7,limit=1e6;
int phi[_];
void Euler() {
    for(int i=1;i<=limit;++i) phi[i]=i;
    for(int i=2;i<=limit;++i) {
        if(phi[i]==i) {
            phi[i]=i-1;
            for(int j=i+i;j<=limit;j+=i)
                phi[j]=(phi[j]/i)*(i-1);
        }
    }
}
std::vector<int> ans;
int main() {
    Euler();
    int n,k;
    cin>>n>>k;
    if(k==1) return puts("3"),0;
    for(int i=3;i<=n;++i) ans.push_back(phi[i]);
    sort(ans.begin(),ans.end());
    long long tot=0;
    for(int i=0;i<k;++i) tot+=ans[i];
    cout<<tot+2<<"\n";
    return 0;
}
相關文章
相關標籤/搜索