BZOJ-2257 [Jsoi2009]瓶子和燃料(裴蜀定理)
题目描述
有 \(n(1\leq n\leq 1000)\) 个瓶子,选择其中的 \(k\) 个来装水,所有的瓶子都没有刻度。第 \(i\) 个瓶子的容量为 \(a_i(1\leq a_i\leq 10^9)\),另一个人可以将某个瓶子装满水,将某个瓶子中的水全部倒掉,将水从瓶子 \(a\) 倒到瓶子 \(b\),直到瓶子 \(b\) 满或瓶子 \(a\) 空,倾倒过程中的损耗可以忽略。找到最优的瓶子组合,使水尽量多。
分析
只考虑两个瓶子,假设瓶子 \(a=3\),瓶子 \(b=5\),第一步把瓶 \(a\) 装满,全都倒进瓶子 \(b\),此时 \(a=0,b=3\);第二步把瓶子 \(a\) 装满,再把 \(a\) 中的水倒入 \(b\),直到 \(b\) 倒满,此时 \(a=1,b=5\),把瓶子 \(b\) 的水全部倒掉,最小值为 \(1\),即 \(2\times 3-5=1\),这恰好是扩展欧几里得的计算过程,根据裴蜀定理,把瓶子数量推广到 \(n\) 个,则最小值为 \(\gcd(a_1,a_2,\cdots,a_n)\)。
因此题目即为从 \(n\) 个数中选择 \(k\) 个,使它们的 \(\gcd\) 最大,分解每个数字并记录约数,数目大于 \(k\) 的最大的约数即为答案。
代码
#include<bits/stdc++.h>
using namespace std;
map<int,int> mp;
int n,k,ans;
void solve(int x)
{
for(int i=1;i*i<=x;i++)
{
if(x%i==0)
{
mp[i]++;
if(mp[i]>=k)
ans=max(ans,i);
if(i*i!=x)
{
mp[x/i]++;
if(mp[x/i]>=k)
ans=max(ans,x/i);
}
}
}
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
solve(x);
}
cout<<ans<<endl;
return 0;
}
posted on 2020-11-28 15:11 DestinHistoire 阅读(75) 评论(0) 收藏 举报