标签:int 题解 Coins 二进制 num maxn bitset include
【题解】Coins(二进制拆分+bitset)
俗话说得好,bitset大法吼啊
这道题要不是他多组数据卡死了我复杂度算出来等于九千多万的选手我还不会想这种好办法233
考虑转移的实质是怎样的,就是对于一个\(dp\)数组表,平移\(val_i \times num_i'\)位然后异或起来,这样就直接bitset开就好了。
背包问题的转移就不说了,优化就是利用二进制来优化,方法就是,我们可以知道所有数都是二进制表示出来的,根据加法交换律以及背包转移的方法,我们从小往大枚举\(2^x\le num_i\),然后把bitset平移\(2^x\)位后异或起来就好了。
但是有个天大的问题就是怎么保证我们的方案合法,也就是说保证我们的方案中不存在硬币用得过多。
实际上直接在循环的时候控制一下就好了,出来的方案就会\(\le num_i\)并且每个组合都会考虑到。
//@winlere
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<bitset>
using namespace std; typedef long long ll;
const int maxm=1e5+5;
const int maxn=1e2+5;
int val[maxn],num[maxn];
bitset < maxm > dp;
int n,m;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(c<48||c>57)f|=c==45,c=getchar();
while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
int main(){
dp[0]=1;int ans=0;
while(scanf("%d%d",&n,&m),n||m){
for(register int t=1;t<=n;++t) val[t]=qr();
for(register int t=1;t<=n;++t) num[t]=qr();
dp&=1;
for(register int t=1;t<=n;++t){
for(register int i=1;i<=num[t];i<<=1)
if(1ll*i*val[t]<=m) dp|=dp<<(i*val[t]),num[t]-=i;
else num[t]-=i;
if(1ll*num[t]*val[t]<=m) dp|=dp<<(num[t]*val[t]);
}
for(register int t=1;t<=m;++t)
if(dp[t]) ++ans;
printf("%d\n",ans);
ans=0;
}
return 0;
}
标签:int,题解,Coins,二进制,num,maxn,bitset,include 来源: https://www.cnblogs.com/winlere/p/10868907.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。