bnu24252 海盗分赃
2015-10-21 16:58
190 查看
题目链接:http://www.bnuoj.com/v3/problem_show.php?pid=24252
这是四川2012年省赛的一道题,背景:海盗分宝藏。大概题意:给你N种价值的物品,物品有两个属性,一个是数量,一个是价值(价值是以2的ai次方表示的)。为了公平起见,求出宝藏分配的最小差(二进制表示)。
思路:当我们把宝藏合成后,即2*2^(n-1)宝藏=1*2^n宝藏(即二进制的进位处理),如果价值最大的宝藏可一分为二,那么该宝藏不会影响最终的结果(即该部分差值为0),如果价值最大的宝藏不可平分,那么必定结果必定是 该宝藏的价值-剩余宝藏的和 。(当进位处理后,差值最小的情况:2^n-(2^(n-2)+2^(n-2)+…+2^2+2^1)=1)。维护一个模拟二进制数组来记录宝藏的分布,比如a[2]=4表示2的2次方的宝藏有4个;然后进行进位处理,这时候我们需要一个标记数组,为什呢?因为当进位后如果某一位是1,这个1有两种情况:1>、这个1是进位得到的,那么它可以转换为比它低一位的2,比如:a[2]=1(进位的到),a[1]=0;这个时候相当于a[1]=2,即宝藏是可分的,不会影响结果。2>、这个1是本身就有的,那么则意味着该宝藏不可分,也就是找到可以得到答案的最大宝藏。很显然我们需要标记进位过程中哪一位的1是由进位得到的(这个过程很重要)。那么剩下的问题就是二进制的相减:题目中的减法很有特点,一定是1000000…(n个0)减去另一个二进制数,我们可以把这个二进制数转换为111111111…(n个1)+1;下面相减的过程就是一个简单的取反过程。代码如下
这是四川2012年省赛的一道题,背景:海盗分宝藏。大概题意:给你N种价值的物品,物品有两个属性,一个是数量,一个是价值(价值是以2的ai次方表示的)。为了公平起见,求出宝藏分配的最小差(二进制表示)。
思路:当我们把宝藏合成后,即2*2^(n-1)宝藏=1*2^n宝藏(即二进制的进位处理),如果价值最大的宝藏可一分为二,那么该宝藏不会影响最终的结果(即该部分差值为0),如果价值最大的宝藏不可平分,那么必定结果必定是 该宝藏的价值-剩余宝藏的和 。(当进位处理后,差值最小的情况:2^n-(2^(n-2)+2^(n-2)+…+2^2+2^1)=1)。维护一个模拟二进制数组来记录宝藏的分布,比如a[2]=4表示2的2次方的宝藏有4个;然后进行进位处理,这时候我们需要一个标记数组,为什呢?因为当进位后如果某一位是1,这个1有两种情况:1>、这个1是进位得到的,那么它可以转换为比它低一位的2,比如:a[2]=1(进位的到),a[1]=0;这个时候相当于a[1]=2,即宝藏是可分的,不会影响结果。2>、这个1是本身就有的,那么则意味着该宝藏不可分,也就是找到可以得到答案的最大宝藏。很显然我们需要标记进位过程中哪一位的1是由进位得到的(这个过程很重要)。那么剩下的问题就是二进制的相减:题目中的减法很有特点,一定是1000000…(n个0)减去另一个二进制数,我们可以把这个二进制数转换为111111111…(n个1)+1;下面相减的过程就是一个简单的取反过程。代码如下
#include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <ctime> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <map> #include <set> #include <string> #define OUT(x) cout << #x << ": " << (x) << endl using namespace std; typedef long long LL; //注意要用long long存 const int maxn=100005; const int INFF=999999999; LL a[maxn]; LL ans[maxn]; bool fg[maxn]; int main() { int T,i,cas=1; scanf("%d",&T); while(T--) { memset(a,0,sizeof a); memset(fg,false,sizeof fg); memset(ans,0,sizeof ans); int n,val,num,max=0; scanf("%d",&n); for(i=0;i<n;i++) { scanf("%d %d",&val,&num); if(max<val) //记录最大价值id max=val; a[val]+=num; } for(i=0;i<=max;i++) { if(a[i]>=2) { a[i+1]+=a[i]/2; //注意好顺序 a[i]%=2; fg[i+1]=true; } } int id=0; for(i=max;i>0;i--) { if(a[i]%2 == 1&& !fg[i]) { id=i; break; } } printf("Case #%d: ",cas++); if(id == 0) //判断 { printf("%lld\n",a[0]); continue; } ans[0]=1; for(i=id-1;i>=0;i--) ans[i]+=(1-a[i]%2); for(i=0;i<=id;i++) if(ans[i]>=2) { ans[i]=0; ans[i+1]++; } for(i=id+1;i>=0;i--) { if(ans[i] == 1) break; } //去除前导0 for(;i>=0;i--) printf("%lld",ans[i]); puts(""); } return 0; }
相关文章推荐
- 新浪项目笔记
- 鼠标滑动--水滴效果
- android listview圆角
- WM_USER以及自定义消息WM_XXXX的定义 声明 实现
- 队列---循环队列
- 表格布局页面
- linux(工具)
- 项目环境配置jar包问题
- iOS 内存管理(strong weak copy)详解
- Android图片处理
- android中具有分隔功能的edittext
- JavaScript完成简单的对联广告
- hbase分页的功能实现
- Weka简介
- Find Median from Data Stream
- 个人觉得比较好的 切使用的sublime text2 插件
- keyPress事件与KeyPressEventArgs
- Maven常用命令
- Nodejs创建HTTPS服务器
- 解析一个邮箱地址的合法性