放下链接趴还是$QwQ$
$A$
题目大意说,给定若干张面额不同的纸币,且面额是倍数关系,每次给至少c元,问钱最多能给几次$QwQ$?
阿显然考虑贪心鸭,,,
首先大于$c$的就不管了,肯定每次用一张就好,所以贡献就钱币数量$QwQ$.
然后对于比$c$小的.我开始想的是每次就优先大的和小的配对,然后自己随手造了一组数据就把自己$hack$了$kk$.
考虑这样儿,就先从大到小,只要小于等于$C$,能取就取,然后如果恰好等于$C$,就把这种方案计入答案,否则再从小到大继续能取就取,直到大于$C$,然后再把这种方案计入答案$QwQ$,一直到凑不出来$C$了(即到最后依然小于$C$)就可以输出答案了,$over$
证明的话,主要就抓住一个关键点,就说大面额一定是小面额的倍数$QwQ$
所以大面额显然不优于小面额$QwQ$,所以在选择的时候一定是先选大面额再选小面额的嘛$QwQ$
然后因为过程中我们一直在保证$\sum \leq C$,所以如果从大到小枚完了依然不能恰好等于$C$,说明此时一定已经不存在恰好等于$C$的方案了,此时再从小往大填补缺少的显然最优,$over$
//#include<bits/stdc++.h> #include<algorithm> #include<iomanip> #include<cstring> #include<cstdio> using namespace std; #define il inline #define int long long #define gc getchar() #define ri register int #define rc register char #define rb register bool #define rp(i,x,y) for(ri i=x;i<=y;++i) #define my(i,x,y) for(ri i=x;i>=y;--i) const int N=30,inf=1e18; int n,C,as,cnt,use[N]; bool gdgs=1; struct node{int val,num;}nod[N]; il int read() { rc ch=gc;ri x=0;rb y=1; while(ch!='-' && (ch>'9' || ch<'0'))ch=gc; if(ch=='-')ch=gc,y=0; while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc; return y?x:-x; } il bool cmp(node gd,node gs){return gd.val<gs.val;} il void cal() { while(gdgs) { memset(use,0,sizeof(use));rb flg=0;ri tmp_c=C; my(i,cnt,1) {ri lim=min(tmp_c/nod[i].val,nod[i].num);tmp_c-=lim*nod[i].val;use[i]=lim;if(!tmp_c){flg=1;i=0;}} if(tmp_c>0) rp(i,1,cnt) { if(nod[i].num>use[i]) while(nod[i].num>use[i]){tmp_c-=nod[i].val;++use[i];if(tmp_c<0){flg=1;break;}} if(flg)i=cnt+10; } if(!flg)return; ri tmp=inf;rp(i,1,cnt)if(use[i])tmp=min(tmp,nod[i].num/use[i]); as+=tmp;rp(i,1,cnt)nod[i].num-=use[i]*tmp; } } signed main() { //freopen("A.in","r",stdin);freopen("A.out","w",stdout); n=read();C=read();rp(i,1,n){ri v=read(),b=read();if(v>C){as+=b;continue;}nod[++cnt]=(node){v,b};} sort(nod+1,nod+1+cnt,cmp);cal();printf("%lld\n",as); return 0; }View Code
$B$
长得就很做过的亚子,,,虽然我忘了到底有麻油做过了$QwQ$
显然考虑二分+贪心?好像都挺$easy$的不想说了,,,
然后最后输出方案的时候注意下,因为要求前面尽量小所以倒着贪心下就好,$over$