这两天贼烦,ccf炸了,还有一个烦心事。哎我都不知道自己能不能坚持下去了。马上期末考了。这段时间还是抓紧时间复习吧同时刷usaco的节奏要跟以前一样了,毕竟课少了。
题解:
只要你知道以下的数论结论,这道题就是水背包了:
有两个数p,q,且gcd(q,p)=1,则最大无法表示成px+qy(x>=0,y>=0)的数是pq-q-p(对于n>pq-q-p,都可以表示成px+qy;而pq-q-p,就无法表示成px+qy)。
而且数越多,这个值只会越小。
所以我们只需考虑小于pq-q-p的范围的最小值。对于一些无解的(全体最大公约数>1),或无数解的(有一个‘1’),应提前判断。 其实我们可以干脆全取上界为256*256-256*2
分析:第一步:判断这 n 个数的gcd,如果 gcd!= 1 则无解;以上证明就是证明红字部分要让大于这个数所有的数都可以表示明显p可以,则p+1肯定可以。得到a式。用反证法证明一下即可知gcd(a1-an)=1;
第二步:如果 gcd=1 则解小于最大的两个数的LCM。
第三步:背包,使用标记数组 d[],d[i]=d[i-a[j]];
简单证明一下:
第一步:
a1*x1+a2*x2+……+an*xn = p;
a1*y1+a2*y2+……+an*yn = p+1;
所以:a1*(y1-x1)+a2*(y2-x2)+……+an*(yn-xn) = 1;
所以:gcd(a1,a2,……,an)*[a1/gcd(a1,a2,……,an)*(y1-x1) + a2/gcd(a1,a2,……,an)*(y2-x2) +……+ an/gcd(a1,a2,……,an)*(yn-xn)]=1(a)
所以:gcd(a1,a2,……,an)=1;
第二步:……
[a1/gcd(a1,a2,……,an)*(y1-x1) + a2/gcd(a1,a2,……,an)*(y2-x2) +……+ an/gcd(a1,a2,……,an)*(yn-xn)]=1/gcd(a1,a2,……,an);
因为等式左边是整数等式右边也是整数所以只能等于1;
然后就是dp找到所有状态。从大到小看那个状态不存在。
/* ID:jinbo wu LANG:C++ TASK: nuggets */ #include<bits/stdc++.h> using namespace std; int dp[256*256]; int a[15]; int gcd(int b,int c) { if(c==0) return b; return gcd(c,b%c); } bool cmp(int a,int b) { return a>b; } int main() { freopen("nuggets.in","r",stdin); freopen("nuggets.out","w",stdout); int n; cin>>n; for(int i=0;i<n;i++) cin>>a[i]; int g=a[0]; if(n==1) { cout<<"0"<<endl; return 0; } for(int i=1;i<n;i++) { g=gcd(g,a[i]); if(g==1) break; } if(g!=1) { cout<<"0"<<endl; return 0; } sort(a,a+n,cmp); dp[0]=1; int sum=a[0]*a[1]-a[0]-a[1]; for(int i=0;i<n;i++) { for(int j=a[i];j<=sum;j++) { if(dp[j-a[i]]) dp[j]=1; } } for(int i=sum;i>=0;i--) { if(!dp[i]) { cout<<i<<endl; return 0; } } }