poj 2886 "Who Gets The Most Candies?"(树状数组)
参考资料:
[1]:http://www.hankcs.com/program/algorithm/poj-2886-who-gets-the-most-candies.html
题意:
抢糖:N个熊孩子围成一个圈,从第K个开始淘汰,每淘汰一个,出示手中的数字,决定下一个淘汰者,正数表示左手第n个,负数反之。每个人可以拿到的存活回数的因数个数的糖果,求拿到最多糖果数的孩子的名字以及糖果数。
(以上题意来自参考资料[1])
下面谈谈我对参考资料[1]的理解:
下面介绍一下相对位置的概念(自己理解的,表达欠缺还请留言告知):
假设初始有 6 个人,编号分别为 1~6
1 2 3 4 5 6(初始编号)
1 2 3 4 5 6(相对位置)
初始编号为2的小盆友离开后,相对位置变为:
1 3 4 5 6(初始编号)
1 2 3 4 5(相对位置)
那么,首先考虑这个问题,如何根据当前离开的小盆友的初始编号 k 和其手中的卡片 x 确定下一个小盆友离开的相对位置?
分两种情况:
假设当前还有 curTot 个小盆友,k 位置前有 before 个小盆友,k 位置后有 after 个小盆友(before + after = curTot);
① x > 0
从 k 位置向右找第 x 个小盆友,相当于从第一个位置的小盆友向右找第 nex=(before+x)%curTot 个小盆友;
因为第一个小盆友的相对位置为 1,所以,需要查找的第 nex 个小盆友的相对位置为 nex+1;
② x < 0
从第 k 位置向左找第 x 个小盆友,相当于从第一个位置的小盆友向左找第 nex=(after+x)%curTot 个小盆友;
当前一共有 curTot 个小盆友,那,相当于从第一个位置的小盆友向右找第 nex= (curTot-nex)%curTot 个小盆友;
因为第一个小盆友的相对位置为 1,所以,需要查找的第 nex 个小盆友的相对位置为 nex+1;
相对位置求出来后,如何求解其对应的初始编号呢???
引用参考资料[1]博主的话就是 “这种区域修改可以活用BIT高效完成”;
怎么个活用法呢?
首先看一下BIT代码:
struct BIT
{
int bit[maxn];
void Init()
{
mem(bit,);
}
void Add(int t,int x)
{
while(t < maxn)
{
bit[t] += x;
t += lowbit(t);
}
}
int Sum(int t)
{
int sum=;
while(t > )
{
sum += bit[t];
t -= lowbit(t);
}
return sum;
}
}_bit;
初始,将 1~n 个小盆友全加入到BIT中;
for(int i=;i <= n;++i)
_bit.Add(i,);
那么,此时初始编号 i 对应的前缀和Sum(i)正好为 i 的相对位置:
i : 1 2 3 4 5 6
_bit.Sum(i) : 1 2 3 4 5 6
假设初始 i = 2 小盆友出队,调用_bit.Add(2,-1)
i : 1 2 3 4 5 6
_bit.Sum(i) : 1 1 2 3 3 4
如果我现在想知道相对位置为3的小盆友的初始编号,该怎么办呢?
你会发现,_bit.Sum(4) = 3,4正好是2好小盆友出队后相对位置为3的小盆友的编号;
那么,想要找相对位置为 pos 的初始编号,只需在_bit.Sum()中找第一个使 _bit.Sun(No) = pos 的No即可;
因为 _bit.Sum() 有序,所以,在查找的时候可以二分查找以提高效率;
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define lowbit(x) (x&-x)
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn=5e5+; int n,k;
char name[maxn][];
int x[maxn];
int factor[maxn];
struct BIT
{
int bit[maxn];
void Init()
{
mem(bit,);
}
void Add(int t,int x)
{
while(t < maxn)
{
bit[t] += x;
t += lowbit(t);
}
}
int Sum(int t)
{
int sum=;
while(t > )
{
sum += bit[t];
t -= lowbit(t);
}
return sum;
}
int BS(int x)
{
int l=,r=n+;
while(r-l > )
{
int mid=l+((r-l)>>);
if(Sum(mid) >= x)
r=mid;
else
l=mid;
}
return r;//使Sum()=x 的第一个位置
}
}_bit;
void factorTable()
{
fill(factor,factor+maxn,);
for(int i=;i < maxn;++i)
{
if(factor[i] != )
continue;
for(int j=i;j <= maxn;j+=i)
{
int k=;
for(int m=j;m%i == ;m/=i,k++);
factor[j] *= k+;//j包含k个质数i
}
}
}
void Solve()
{
int candy=;
int index;
for(int i=;i <= n;++i)
{
if(candy < factor[i])
{
candy=factor[i];//更新candy
index=k;//第i个出队的编号是k(初始编号)
}
if(i == n)
break; _bit.Add(k,-);
int nex;
int curTot=n-i;//当前剩余小盆友的个数
if(x[k] > )//情况①
{
nex=(x[k]+_bit.Sum(k)-)%curTot;
nex++;
}
else//情况②
{
x[k]=-x[k];
nex=(x[k]+curTot-_bit.Sum(k))%curTot;//向左找第nex个
nex=(curTot-nex)%curTot;//转化为向右找
nex++;
}
k=_bit.BS(nex);//二分查找相对位置为nex的初始编号
}
printf("%s %d\n",name[index],candy);
}
int main()
{
factorTable();//预处理出因子表
while(~scanf("%d%d",&n,&k))
{
_bit.Init();
for(int i=;i <= n;++i)
{
scanf("%s%d",name[i],x+i);
_bit.Add(i,);
}
Solve();
}
return ;
}

其实,这道题被我搁置四天了,当时按照自己的思路写了个线段树的,wa了;
改了许久无果,无奈,搜了搜题解,第一个题解看的就是参考资料[1],
不过,当时没怎么理解,又找了找其他人的博客,学到了一个新概念--反素数(可以提前打出反素数表,也可以提前打出因子表);
这几天,训练赛几乎每天都有,忙着训练,忙着补题;
这道题只是在我闲暇时光看看,捋捋思路;
昨天晚上终于有点懵懂;
今天,又花费了一个多小时,终于AC了,不过,和[1]博主的代码不太一样,[1]博主的代码我还没怎么,理解透呢,只是有点懵懂;
或许,这就是大佬吧,写出的代码得让吾等蒟蒻看好久才能理解Orz
poj 2886 "Who Gets The Most Candies?"(树状数组)的更多相关文章
- POJ 2886 Who Gets the Most Candies?(树状数组+二分)
题目链接 注意题目中给的顺序是顺时针的,所以在数组中应该是倒着存的.左就是顺时针,右就是逆时针.各种调试之后,终于A了,很多种情况考虑情况. #include <cstring> #inc ...
- poj 1195:Mobile phones(二维树状数组,矩阵求和)
Mobile phones Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 14489 Accepted: 6735 De ...
- POJ 2352 && HDU 1541 Stars (树状数组)
一開始想,总感觉是DP,但是最后什么都没想到.还暴力的交了一发. 然后開始写线段树,结果超时.感觉自己线段树的写法有问题.改天再写.先把树状数组的写法贴出来吧. ~~~~~~~~~~~~~~~~~~~ ...
- [poj 1533]最长上升子序列nlogn树状数组
题目链接:http://poj.org/problem?id=2533 其实这个题的数据范围n^2都可以过,只是为了练习一下nlogn的写法. 最长上升子序列的nlogn写法有两种,一种是变形的dp, ...
- POJ 2985 The k-th Largest Group(树状数组 并查集/查找第k大的数)
传送门 The k-th Largest Group Time Limit: 2000MS Memory Limit: 131072K Total Submissions: 8690 Acce ...
- POJ 1195 Mobile phones(二维树状数组)
Mobile phones Time Limit: 5000MS Mem ...
- POJ 3321 Apple Tree(dfs序树状数组)
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=10486 题意:一颗有n个分支的苹果树,根为1,每个分支只有一个苹果,给出n- ...
- POJ 2892 Tunnel Warfare || HDU 1540(树状数组+二分 || 线段树的单点更新+区间查询)
点我看题目 题意 :N个村子连成一条线,相邻的村子都有直接的地道进行相连,不相连的都由地道间接相连,三个命令,D x,表示x村庄被摧毁,R ,表示最后被摧毁的村庄已经重建了,Q x表示,与x直接或间 ...
- 【POJ 3167】Cow Patterns (KMP+树状数组)
Cow Patterns Description A particular subgroup of K (1 <= K <= 25,000) of Farmer John's cows l ...
- POJ 1195 Mobile phones (二维树状数组或线段树)
偶然发现这题还没A掉............速速解决了............. 树状数组和线段树比较下,线段树是在是太冗余了,以后能用树状数组还是尽量用......... #include < ...
随机推荐
- Java开发环境的搭建01——Eclipse篇(Windows)
搭建环境是换项目组和新入职的开发入项都必须面临的一件事情,搭搭环境,一天就过去了...本着不浪费生命不做重复的无用功,在这里写写环境搭建的基本功,这篇是介绍Java环境搭建,常见的开发IDE无非就两种 ...
- cisco 下CEF(简介)[转载]
cisco 下CEF(简介) 转自:http://blog.51cto.com/chengmingshu/803358 cms_cmd1人评论2570人阅读2012-03-12 00:09:29 ...
- Ngnix负载均衡安装及配置
1.ngnix概念 Nginx是一款高性能的http 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器.由俄罗斯的程序设计师Igor Sysoev所开发,官方测试nginx能够支支撑5 ...
- winserver-查看登陆日志
Abstract 先要开启登陆审核,在查看登陆日志. 开启审核 运行 secpol.msc 日志查看 windowslog 下的security 管理员成功登陆后的eventid:4776,4648, ...
- SQL Server数据仓库的基础架构规划
问题 SQL Server数据仓库具有自己的特征和行为属性,有别去其他.从这个意义上说,数据仓库基础架构规划需要与标准SQL Server OLTP数据库系统的规划不同.在本文中,我们将介绍在计划数据 ...
- C# -- 使用 Task 执行多线程任务
C# -- 使用 Task 执行多线程任务 1. 使用 Task 执行多线程任务 class Program { static void Main(string[] args) { Task task ...
- Microsoft Visual Studio 2012 添加实体数据模型
Microsoft Visual Studio 2012 添加实体数据模型 1.创建一个web项目 2.添加ADO实体数据模型,如下图: 3.选择 从数据库生成,然后下一步 4.新建连接,如下图: ...
- 伺服电机&旋转变压器&光电编码器
旋转变压器与光电编码器是目前伺服领域应用最广的测量传感器. 一.伺服系统 又称为随动系统,精确的跟随或者复现某个过程的反馈系统. 使物体的位置.方位.状态等输出被控量能够跟随目标(设定)的任意变化的自 ...
- 你不需要 jQuery,但你需要一个 DOM 库
写这篇文章的目的,一方面是介绍一下自己编写的模块化 DOM 库 domq.js,另一方面是希望大家对 jQuery 有一个正确的认识,即使 jQuery 已经逐渐退出历史舞台,但是它的 API 将会以 ...
- Angular 基本内置服务和筛选器
AngularJS中的内置服务(共30多个): $http 发送http请求,主要用于进行异步数据请求的功能实现,这个服务主要封装了XMLHttpRequest对象和JSONP数据访问模式来完成远程请 ...