• 【题解】Coins(二进制拆分+bitset)


    【题解】Coins(二进制拆分+bitset)

    【vj】

    俗话说得好,bitset大法吼啊

    这道题要不是他多组数据卡死了我复杂度算出来等于九千多万的选手我还不会想这种好办法233

    考虑转移的实质是怎样的,就是对于一个(dp)数组表,平移(val_i imes num_i')位然后异或起来,这样就直接bitset开就好了。

    背包问题的转移就不说了,优化就是利用二进制来优化,方法就是,我们可以知道所有数都是二进制表示出来的,根据加法交换律以及背包转移的方法,我们从小往大枚举(2^xle 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
    ",ans);
    	    ans=0;
          }
          return 0;
    }
    
    
  • 相关阅读:
    java连接oracle
    用js实现登录的简单验证
    合并链表,按主键升序
    Jquery中.ajax和.post详解
    简洁的Jquery弹出窗插件
    服务端缓存页面及IIS缓存设置
    C#托管代码、非托管代码及回收机制
    页面滑动底部自动加载下一页信息
    EF各版本增删查改及执行Sql语句
    Node.Js and Mongoose
  • 原文地址:https://www.cnblogs.com/winlere/p/10868907.html
Copyright © 2020-2023  润新知