1. 程式人生 > 實用技巧 >Luogu4571 [JSOI2009]瓶子和燃料(裴蜀定理)題解

Luogu4571 [JSOI2009]瓶子和燃料(裴蜀定理)題解

前置芝士

裴蜀定理

\(a\)\(b\)是整數,且\(gcd(a,b)=d\),那麼對於任意的整數\(x\)\(y\)\(ax+by\)都一定是\(d\)的倍數,特別地,一定存在整數\(x\)\(y\),使\(ax+by=d\)成立。

推廣: \(a_1,a_2,a_3...a_n\)\(n\)個整數,\(d\)是它們的最大公約數,那麼存在整數\(x_1...x_n\)使得\(x_1\times a_1+x_2\times a_2+...x_n\times a_n=d\)

思路

根據裴蜀定理,外星人所給出的燃料數量為\(k\)個瓶子容積的\(gcd\)。因此問題就轉化為:從\(n\)

個數中選出\(k\)個數,使得它們的\(gcd\)最大。

我們可以將每個數的因數分解出來(並不只是質因數),記錄每一個因子的出現次數,排序以後選出最大的出現次數\(\geq k\)的就可以了。

另外,本題數值較大,需要開\(map\)

參考程式碼

#include <cstdio>
#include <algorithm>
#include <map>

using namespace std;

const int maxn = 1e6 + 10;
int n,cnt,k;
struct Num{
    int val,num;
}p[maxn];
map<int,int> T;

bool cmp(Num x, Num y){return x.val > y.val;}

int main(){
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; ++ i){
        int v; scanf("%d", &v);
        for(int j = 1; j * j <= v; ++ j){
            if(v % j == 0){
                if(!T[j]) T[j] = ++ cnt, p[cnt].val = j, p[cnt].num ++;
                else p[T[j]].num ++;
                int fff = v / j;
                if(fff == j) continue;
                if(!T[fff]) T[fff] = ++ cnt, p[cnt].val = fff, p[cnt].num ++;
                else p[T[fff]].num ++;
            }
        }
    }
    sort(p + 1, p + 1 + cnt, cmp);
    for(int i = 1; i <= cnt; ++ i)
        if(p[i].num >= k) return printf("%d\n", p[i].val), 0;
    return 0;
}