P1582倒水
推了一个多小时的式子,ac后一看题解,7行代码搞定
emmmm我还是太菜了
蒟蒻解法:
不管怎么倒水,最终所有瓶子里面的水的数量一定可以用2k表示出来。
n最终可以合并成几个瓶子呢?
我们可以把n分解为多个2k相加的形式,例如:13=23+22+20,所以13最少合并到3个瓶子里面
求n最少能合并到几个瓶子里面,正是看n的二进制表示里面有多少个1
如果1的数量cnt小于等于k,则直接输出0。
否则:从第一个是1的位置+1开始,扫到cnt-k+1个1的位置,中间如果是0,ans就加上2是0的位置,最后ans+2第一个是1的位置
粗略的解释一下
假设某个数的二进制表示是1000101001000,k=2
加上23:1000101010000
加上24:1000101100000
加上25:1000110000000
加上27:1001000000000
对比刚开始的n:100101001000
标0的是加完后最后一个1所在的位置。
我们发现在原始的n的第一个1开始,一直到cnt-k+1的1的位置,中间是0的地方都要在答案上加2k(当然第一个是1的地方除外)
maybe代码会好懂一些
#include<bits/stdc++.h>
using namespace std;
int n,a[],b[],cnt,k,now,ans;//a[i]记录n的二进制表示中,2^i所对应的位上是0还是1,b[i]记录第i个1的位置
long long mi[];//mi[i]为2^i
int read()
{
char ch=getchar();
int x=; bool f=;
while(ch<''||ch>'')
{
if(ch=='-')
f=;
ch=getchar();
}
while(ch>=''&&ch<='')
{
x=(x<<)+(x<<)+(ch^);
ch=getchar();
}
return f?-x:x;
}
void init()
{
mi[]=;
for(int i=;;i++)
{
mi[i]=mi[i-]*;
if(mi[i]>n)break;//mi不开long long见祖宗
}
}
int main()
{
n=read();k=read();
init();
while(n)
{
a[now]=n&;//now代表当前是2^now所代表的位置
if(n&)
{
b[++cnt]=now;
}
now++;
n>>=;
}
if(cnt<=k)//特判
{
printf("");return ;
}
int m=cnt-k+;
ans+=mi[b[]];
for(int i=b[]+;i<=b[m];i++)
{
if(a[i]==)ans+=mi[i];
}
printf("%d\n",ans);
}
大佬做法:
因为所有的水都是由两份相同的水合并而成的,因此每瓶水的体积一定是2^i,(i\in N)2i,(i∈N)升。
最后保留k个瓶子,那么最后总的升数的二进制表示中,1的个数一定<=k。
那么我们只要贪心地往n上加上lowbit(n)即可。
这个lowbit就是树状数组那个lowbit啦
简化代码的trick:
使用内置函数\_\_builtin\_popcount()
来计算一个数的二进制表示中1的数量。
这样下来,代码简化到仅剩7行。
惊不惊喜,意不意外?
------------------------摘自洛谷第一篇题解
#include <cstdio>
int n, k, ans;
int main() {
scanf("%d%d", &n, &k);
while(__builtin_popcount(n) > k) ans += n & -n, n += n & -n;
printf("%d", ans);
}
P1582倒水的更多相关文章
- 洛谷 P1582 倒水 解题报告
P1582 倒水 题目描述 一天,CC买了N个容量可以认为是无限大的瓶子,开始时每个瓶子里有1升水.接着~~CC发现瓶子实在太多了,于是他决定保留不超过K个瓶子.每次他选择两个当前含水量相同的瓶子,把 ...
- P1582 倒水 (数学)
P1582 倒水 题目描述 一天,CC买了N个容量可以认为是无限大的瓶子,开始时每个瓶子里有1升水.接着~~CC发现瓶子实在太多了,于是他决定保留不超过K个瓶子.每次他选择两个当前含水量相同的瓶子,把 ...
- 洛谷P1582 倒水
P1582 倒水 题目描述 一天,CC买了N个容量可以认为是无限大的瓶子,开始时每个瓶子里有1升水.接着~~CC发现瓶子实在太多了,于是他决定保留不超过K个瓶子.每次他选择两个当前含水量相同的瓶子,把 ...
- 洛谷P1582 倒水 二进制 lowbit __builtin_popcount
P1582 倒水:https://www.luogu.org/problemnew/show/P1582 题意: 给定n瓶装有1升的水瓶,每次可以把两瓶装水量相同的水和成一瓶,问最少还要增加几瓶装有1 ...
- 洛谷 - P1582 - 倒水 - 位运算
https://www.luogu.org/problemnew/show/P1582 要求用最少的瓶子,那肯定不能有两个一样的瓶子,否则合并更优. 枚举其二进制位,每次加上lowbit,将最后一个1 ...
- 洛谷P1582 倒水 二进制的相关应用
https://www.luogu.org/problem/P1582 #include<bits/stdc++.h> using namespace std; long long N,K ...
- P1582 倒水(贪心 + lowbbit)
https://www.luogu.com.cn/problem/P1582 #include <bits/stdc++.h> using namespace std; #define i ...
- P1582 倒水
传送门 思路: 类似于 袁绍的刁难 , 一道二进制的模拟题. 先将:将原先的瓶子数 n 转换成二进制,二进制中 1 的个数就是合并后剩下的瓶子个数 . 主要利用树状数组的 lowbit 函数: inl ...
- 洛谷P1582 倒水题解
题目 分析 这个题并不难,只是需要仔细思考我们首先可以很轻松的把这个题给疏通一下题意. 1:首先我们最后每个瓶子中装的水一定是一个$2^x$,因为每次都是$2$倍的加,这个应该很好理解. 2:我们要明 ...
随机推荐
- Mac入门--如何使用brew安装多个PHP版本
一 安装7.1 1. 安装PHP7.1 brew install php@7.1 2. 修改配置 php-fpm.conf,一般在/usr/local/etc/php下(如果php-fpm.conf中 ...
- python列表-增强的赋值操作
增强赋值公式 (1) (2) (3) (4)
- 《剑指offer》面试题18 树的子结构 Java版
(输入两棵二叉树A和B,判断B是不是A的子结构.补充下,根据书中的代码来看,子结构的定义并不包括叶子节点下的null,也就是说只要B的存在数字的结构存在于A中就行,那么如果B是null树,那么就不属于 ...
- 3.Golang的包导入
1.golang的源码文件可以随意命名,但是属于同一个包的源文件必须声明 package base 2.golang的包引入规则 import ( "fmt" #系统包直接写名字 ...
- Linux awk抓取IP的两种方式
ip addr show ens33 | awk -F "[ /]+" '/inet /{print $3}' 或 ifconfig ens33 | awk -F "[ ...
- ES6——generator-yield
yield 既可传参,又可以返回 第一个next()传参无效,只用来启动 如果函数前漏掉 * 就是普通函数 如果有yield会报错, ReferenceError: yield is not defi ...
- meter标签度量衡如何改变颜色
此文章为转载,目的为了方便整理学习笔记. 在meter中要想改变颜色,需要用到五个值,分别是:min(最小值).max(最大值).low.high.value和optimum,其中前四个值会把整个进度 ...
- C# List<object> 按特定字段排序
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using S ...
- UNIX网络编程总结四
socket: 为了执行网络I/O,一个进程做的第一件事就是调用socket函数. family指明协议族,type指明类型,除非在原始套接口,protocol一般为0,并非所有的family,typ ...
- python3.7爬取墨菲定律保存在本地txt
#!/usr/local/bin/python3.7 # -*- coding: utf-8 -*- # @Time: 2019/07/15 # @Function 获取在线文本内容 import r ...