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
  • 相关阅读:
    【纯水题】POJ 1852 Ants
    【树形DP】BZOJ 1131 Sta
    【不知道怎么分类】HDU
    【树形DP】CF 1293E Xenon's Attack on the Gangs
    【贪心算法】CF Emergency Evacuation
    【思维】UVA 11300 Spreading the Wealth
    【树形DP】NOI2003 逃学的小孩
    【树形DP】BZOJ 3829 Farmcraft
    【树形DP】JSOI BZOJ4472 salesman
    【迷宫问题】CodeForces 1292A A NEKO's Maze Game
  • 原文地址:https://www.cnblogs.com/cdcq/p/12242391.html
Copyright © 2011-2022 走看看