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:我们要明 ...
随机推荐
- mooc-IDEA 列操作--005
十一.IntelliJ IDEA -列操作 实例:根据HTTP请求JSON文件,生成一个枚举类 Step1:创建一个枚举类,把要转换的JSON串粘贴进来. 最终要实现效果 Step2:选中第一个100 ...
- Node.js实战12:fs模块高级技巧。
通过fs模块使用流 fs模块同样有流接口,如下例: var fs = require("fs"); var read_able = fs.createReadStream(&quo ...
- STL关联容器值hashtable
hashtable(散列表)是一种数据结构,在元素的插入,删除,搜索操作上具有常数平均时间复杂度O(1); hashtable名词 散列函数:负责将某一元素映射为索引. 碰撞(collision):不 ...
- HDFS镜像文件fsimage和编辑日志文件edits
镜像文件和编辑日志文件 1)概念 namenode被格式化之后,将在/opt/module/hadoop-2.7.2/data/tmp/dfs/name/current目录中产生如下文件 edits_ ...
- document.domain location.hostname location.host
document.domain location.hostname location.host :https://www.cnblogs.com/shd-study/p/103031 ...
- 通过总线机制实现自动刷新客户端配置(Consul,Spring Cloud Config,Spring Cloud Bus)
通过总线机制实现自动刷新客户端配置 方案示意图 利用Git服务的webhook通知功能,在每次更新配置之后,Git服务器会用POST方式调用配置中心的/actuator/bus-refresh接口,配 ...
- Codeforces 990C (模拟+组合数学)
题面: 传送门 分析: 此题O(n2l)" role="presentation" style="position: relative;">O( ...
- 解决Vscode编辑器不能打开多标签页问题
问题描述:编辑代码时,初用vscode,不能打开多个文件:每打开一个文件,都会替换前面一个文件标签,很不方便切换编码: 想要的效果: 解决方式: 方法一: 找到setting.json文件,最外层花括 ...
- C# 开发 Windows 服务 使用Log4net 组件 不能生成日志文件
使用VS2012开发Windows服务,需要使用Log4net日志组件记录业务情况,但是始终生成不了日志文件. /// <summary> /// 入口方法 /// </summar ...
- 带你一文搞定 IO 流相关核心问题
问:简单谈谈 Java IO 流各实现类的特性? 答:java.io 包下面的流基本都是装饰器模式的实现,提供了各种类型流操作的便携性,常见的流分类如下. 以二进制字节方式读写的流: InputStr ...