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
  • 相关阅读:
    Linux IO接口 监控 (iostat)
    linux 防火墙 命令
    _CommandPtr 添加参数 0xC0000005: Access violation writing location 0xcccccccc 错误
    Visual Studio自动关闭
    Linux vsftpd 安装 配置
    linux 挂载外部存储设备 (mount)
    myeclipse 9.0 激活 for win7 redhat mac 亲测
    英文操作系统 Myeclipse Console 乱码问题
    Linux 基本操作命令
    linux 查看系统相关 命令
  • 原文地址:https://www.cnblogs.com/zlhdbk/p/12777890.html
Copyright © 2011-2022 走看看