zoukankan      html  css  js  c++  java
  • CF1303D 位运算+贪心

    CF1303D

    题目大意:

    有一个大小为n的背包,有m个大小为2i(i=0,1,2,3...)的物品,并且每个物品可以分成大小相同的两份,可以一直分成到大小为1为止,问能否用这些物品把背包恰好填满,如果能填满,输出拆分物品的最小次数。

    解题思路:

    通过二进制的方法,从高位到低位贪心的一位一位处理。

    比如样例一:

    10  3

    1   32   1

    n=10,转换成二进制为1010,所以我们看成是1000+10.

    三个物品转换成二进制分别为:1   100000  1

    那么我们用一个dp[i]来表示第i位上有多少个1,比如上述的三个物品转换成dp数组就是dp[0]=2,dp[5]=1,其余都为0。

    那么我们只需要从n对应的二进制的第0位开始与dp[]进行比较,如果dp[i]上的数量可以满足n的要求,则直接减去,否则就需要拆分较大的物品,即为向上借位。

    具体可以看代码及其注释

     1 #include <iostream>
     2 #include <cstring>
     3 #include <string>
     4 #include <algorithm>
     5 #include <queue>
     6 #include <stack>
     7 #include <stdio.h>
     8 #include <cmath>
     9 #include <string.h>
    10 
    11 using namespace std;
    12 #define ll long long
    13 static const int WHITE=0;
    14 static const int GRAY=1;
    15 static const int BLACK=2;
    16 static const int INF=0x3f3f3f3f;
    17 ll Pow(ll a,ll b,ll mod){if(b==0) return 1%mod; ll sum=1; a=a%mod; while(b>0) { if(b%2==1) sum=(sum*a)%mod; b/=2; a=(a*a)%mod;}return sum;}
    18 int dp[35];//用来记录第i位上有多少个1
    19 void change(int a)//由于物品的大小都是2的n次方,所以其二进制一定为1000---的形式
    20 {
    21     int k=0;
    22     while((a>>k)>1)//找到该数的二进制的1在第几位
    23     k++;
    24     dp[k]++;
    25 }
    26 int main()
    27 {
    28     freopen("C:\Users\16599\Desktop\in.txt","r",stdin);
    29     int T;
    30     cin>>T;
    31     while (T--)
    32     {
    33         memset(dp,0,sizeof(dp));
    34         ll n,m,sum;
    35         sum=0;
    36         cin>>n>>m;
    37         for(int i=1;i<=m;i++)
    38         {
    39             int a;
    40             cin>>a;
    41             sum+=a;
    42             change(a);
    43         }
    44         if(sum<n)//全部装进都装不满
    45         {
    46             cout<<"-1"<<endl;
    47             continue;
    48         }
    49         int p=0,num=0;
    50         while(n||dp[p]<0)
    51         {
    52             dp[p]-=n&1;//n&1是用来判断n转换成二进制后的最低位是否为1
    53             if(dp[p]<0)//如果物品的对应位置不能满足n的需求,则需要向高位借位
    54             {
    55                 dp[p+1]--;
    56                 num++;//较大物品拆分,次数加一
    57             }
    58             else
    59             dp[p+1]+=dp[p]/2;//如果低位有的多,可以给高位用
    60             n>>1;//n的最低为处理完成,进一位
    61             p++;
    62         }
    63         cout<<num<<endl;
    64     }
    65     
    66     return 0;
    67 }
    View Code
  • 相关阅读:
    git环境搭建、git详细使用教程、快速上手git
    数据一致性解决方案实践
    锁的使用
    数据库连接池优化
    多级缓存优化实践
    服务端调优与JVM调优
    Sentinel 流量防卫兵
    Spring Cloud Gateway微服务网关
    OpenFeign与负载均衡
    Nacos config原理
  • 原文地址:https://www.cnblogs.com/zlhdbk/p/12777890.html
Copyright © 2011-2022 走看看