zoukankan      html  css  js  c++  java
  • 【洛谷1582】倒水

    原题:

    首先注意看清题,题目并不是要求拼出n体积的水,而是现在有n个1L水,要求将瓶压缩至不超过k个

    首先可以考虑一下如果不引入新瓶,原来的瓶子最少能压缩到多少个

    先尝试两种策略,一种是尽量找大的合并,如1 1 1 1 1 1 1-> 2 2 2 1 -> 4 2 1

    另一种是尽量找小的合并,如1 1 1 1 1 1 1 -> 2 2 2 1 -> 4 2 1

    其实是没得区别的233

    最后的结果都是把原来的瓶子数n的每一个二进制位拆出来

    由此可以联想到瓶子内的水总是2的幂次,合并就相当于把两个同位的1合并成一个高位的1

    那么n个瓶子最少能压缩到多少个,本质上是问十进制数n最少能用多少个二进制位的1表示

    显然答案就是n的二进制位个数

    形式化的证明似乎也不难,不过这种结论比较显然,大力猜想就行了

    n的二进制位个数可能仍然大于k,此时需要不同位的两个1压缩

    只能购买新瓶把低位合并到和高位的1同位再合并,才能让瓶数-1

    新买的瓶子首先要能拼成和低位的1同位的1

    可以用lowbit快速取到最低位的1,让其提高一位的代价就是lowbit(n)

    买lowbit(n)个瓶子拼成一个容量为lowbit(n)的瓶子,即可跟lowbit(n)的瓶子合并

    如此循环,直到低位的1被提高到和更高位的1同位时,总瓶数就-1

    不必特意判断增加lowbit(n)后瓶数是否-1,只需让n+=lowbit(n),然后重新求n的二进制位1的个数

    直到个数<=k为止

    注意一个坑,n<=2e9可以int装,但是假设k=1,那么最后拼出的瓶子体积大概达到4e9,需要longlong或者uint

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 long long n,m,o;
     5 int gto(long long  x){
     6     int z=0;
     7     for(;x;x>>=1)  z+=(x&1);
     8     return z;
     9 }
    10 long long lbt(long long x){  return x&-x;}
    11 int main(){
    12     cin>>n>>m;
    13     o=gto(n);
    14     long long ans=0;
    15     while(o>m){
    16         ans+=lbt(n);
    17         n+=lbt(n);
    18         o=gto(n);
    19     }
    20     cout<<ans<<endl;
    21     return 0;
    22 }
    View Code
  • 相关阅读:
    ibatisnet系列
    jQuery弹出层演示
    winform中datagridview的用法
    ASP.net:截取固定长度字符串显示在页面,多余部分显示为省略号
    hdu 4507 恨7不成妻(求l,r中与7不相关数字的平方和)
    hdu 2089 数位dp
    uestc 1307 统计数位之间相差不小于2的数的个数
    Spoj 2319 数位统计(0,1, 2^k1 这些数分成M份)
    zoj 3416 统计平衡数个数
    数位统计 sgu 390 <浅谈数位类问题>
  • 原文地址:https://www.cnblogs.com/cdcq/p/12242391.html
Copyright © 2011-2022 走看看