一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情。
这道题涉及一个数论,如果不知道这个定理可能做题有一些困难。
题目
裴蜀定理
首先介绍一个数论,裴蜀定理。如果有两个数字a,b,他们之间的最大公约数为gcd,那么对于任意的整数x,y,ax+by都一定是gcd的倍数,也一定存在整数x,y使得ax+by=gcd。n个数字的推广:若a1,a2,...,an的最大公约数为gcd,则任意x1,x2,....,xn使得a1X1+a2X2+....+anXn是gcd的倍数,也一定存在整数x1,x2,x3...xn,a1X1+a2X2+....+anXn=gcd。
思路
现在我们这样想,如果两个数字a,b公约数gcd不为1,那么他们凑不出的数一定是无限个的,因为任意整数x,y都是gcd的倍数,所以一定是肯定是有无数个数是凑不出来的。而如果gcd为1,那么就一定不会有无数个数字是凑不出来的。但还是会有一些数字无法凑出来的,因为ax+by=1,x和y是有可能为负数的。现在包子有n个,也就是n个数字,我们就可以用上面裴蜀定理的推广来做了。先求出这n个数字的最大公约数,判断是否为1,如果不为1,之间返回INF。如果为1,我们就可以运用完全背包来完成这道题了。
代码
#include <bits/stdc++.h>
using namespace std;
int bz[110]={0};
int dp[100010]={0};
int gcd(int a,int b){
while(b){
int c=0;
c=b;
b=a%b;
a=c;
}
return a;
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>bz[i];
}
if(n==1&&bz[0]==1)
{
cout<<0;
return 0;
}else if(n==1)
{
cout<<"INF";
return 0;
}
sort(bz,bz+n);
int cnt=gcd(bz[0],bz[1]);
if(n>2)
for(int i=2;i<n;i++){
cnt=gcd(cnt,bz[i]);//求出最大公约数
}
if(cnt!=1)
{
cout<<"INF";
return 0;
}
int ans=0;
dp[0]=1;
for(int j=0;j<n;j++){
for(int i=bz[j];i<=10000;i++)
dp[i]|=dp[i-bz[j]];//这里用按位或运算
}
for(int i=1;i<=10000;i++){
if(!dp[i])
ans++;
}
cout<<ans;
return 0;
}