POJ 2886 Who Gets the Most Candies? 树状数组+二分
一、题目大意
我们有N个孩子,每个人带着一张卡片,一起顺时针围成一个圈来玩游戏,第一回合时,第k个孩子被淘汰,然后他说出他卡片上的数字A,如果A是一个正数,那么下一个回合他左边的第A个孩子被淘汰,如果A是一个负数,那么下一个回合,他右边的第(-A)个孩子被淘汰,如下图所示,即A>0,向着下标增大的方向,A<0,向着下标减小的方向。
其中,第 i (1<=i<=N)回合被淘汰的孩子,可以得到F(i)颗糖果,F(i)代表可以整除 i 的因子的数量(包括1和它本身),最终需要输出 N 个孩子中,得到最多的孩子的名字和他得到的糖果数量,假如说有多个孩子都得到这个糖果数量,输出那个最先被淘汰的。
二、解题思路
首先看这个F(i)代表整除 i 的数量,然后针对输入的 N,我们要找出其中使得 F(i)最大的i,同时如果有多个 i 的F(i)一样,取那个最小的 i。
我们可以定义一个数组F[i],对于某一个数字 i,只需要枚举 [1,根号i取整] 范围内的数字 j ,然后如果 i % j == 0,F[i]+=2(因为 j 和 i / j 都是整除 i 的因子,所以需要都加上)然后若 j == i / j ,那么F[i]+=1即可,因为两个乘数相等了。
然后我们根据输入的 N,要迅速找到其中 i ∈[1,N]且 F[i]最大的i,那么考虑可先打表,计算好F[i]数组之后,从1到500000循环,定义一个数组optF,其中optF[i]代表 j∈[1,i]时,使得 f[j]最大的j。给optF[0]=0,然后1<=i<=500000循环,如果F[i]>optF[i-1],则optF[i]=i,否则optF[i]=optF[i-1],这样可以达到两点,1、对于给定的N,直接用optF[N]可以迅速定位到 j ∈ [1,N],使F[j]最大的j。2、当F[p]==F[p+k]时,因为时从1循环,以大于为条件,所以当 p <=N且 p+k<=N时,我们会找到满足条件的顺序最靠前的p。
举个例子吧,
1、N∈[1,1]时,最大的因子数是1,N以内最优的数字也是1;
2、N∈[2,3]时,最大的因子数是2,N以内最优的数字是2;
3、N∈[4,5]时,最大的因子数是3,N以内最优的数字是4;
4、N∈[6,11]时,最大的因子数是4,N以内最优的数字是6;
4、N∈[12,23]时,最大的因子数是6,N以内最优的数字是12;
那么来分析下复杂性,计算F数组的值需要的时间复杂性是 O ( N * 根号N),根据F数组,计算optF数组的复杂性是O(N),对于500000的数据量, O ( N * 根号N)太慢了。那么我们考虑下,hi发现针对 N<=23时,我们只需要记录4个区间的边界和最优的那个F[i]即可。那么对于500000个数字呢?我试了下发现只有35个区间,于是果断写程序把这35个区间的右边界、左边界和最优数字的因子数的打出来的,打表的程序如下。(我发现每次的左边界就是最优数字)
#include <iostream>
using namespace std;
typedef pair<int, int> P;
P tbl[500009];
int f[500009], optF[500009], len;
void initF()
{f[0] = 0;for (int i = 1; i <= 500000; i++){f[i] = 0;for (int j = 1; j * j <= i; j++){if (i % j == 0){f[i] = f[i] + 2;if (j * j == i){f[i] = f[i] - 1;}}}}
}
void initOptF()
{optF[0] = 0;for (int i = 1; i <= 500000; i++){if (f[i] > f[optF[i - 1]]){optF[i] = i;}else{optF[i] = optF[i - 1];}}
}
void printTbl()
{len = 1;tbl[1] = P(1, optF[1]);for (int i = 2; i <= 500000; i++){if (tbl[len].second == optF[i] && i > tbl[len].first){tbl[len].first = i;}else if (tbl[len].second != optF[i]){tbl[++len] = P(i, optF[i]);}}for (int i = 1; i <= len; i++){printf("%d %d %d\n", tbl[i].first, tbl[i].second, f[tbl[i].second]);}printf("%d\n", len);
}
int main()
{initF();initOptF();printTbl();return 0;
}
这样的话,根据任意的N,找出 i ∈[1,N],且F[i]最大的 i(存在F[i]和F[i+k]相同时,自动定到F[i]),同时算出F[i]的值,可以直接根据这张表在O(1)时间内完成。
int n_Tbl[] = {1, 3, 5, 11, 23, 35, 47, 59, 119, 179, 239, 359, 719, 839, 1259, 1679, 2519, 5039, 7559, 10079, 15119, 20159, 25199, 27719, 45359, 50399, 55439, 83159, 110879, 166319, 221759, 277199, 332639, 498959, 500000};
int k_Tbl[] = {1, 2, 4, 6, 12, 24, 36, 48, 60, 120, 180, 240, 360, 720, 840, 1260, 1680, 2520, 5040, 7560, 10080, 15120, 20160, 25200, 27720, 45360, 50400, 55440, 83160, 110880, 166320, 221760, 277200, 332640, 498960};
int f_Tbl[] = {1, 2, 3, 4, 6, 8, 9, 10, 12, 16, 18, 20, 24, 30, 32, 36, 40, 48, 60, 64, 72, 80, 84, 90, 96, 100, 108, 120, 128, 144, 160, 168, 180, 192, 200};
假设,根据N我们找到那个最优数字是optOrder,然后接下来需要考虑的就是,如何找到第 optOrder 个被淘汰的孩子呢?
我的思路是模拟出整个游戏的过程,维护一个树状数组,起初的时候给[1,N]内所有的元素的位置都+1,然后每当第x位置的孩子淘汰的时候,给树状数组update(x,-1)。
使用树状数组+二分查找可以迅速找到当前没有被淘汰的孩子中的第 q 个q∈[1,len],len为当前内有被淘汰的孩子数量,
1、 L = 0 ,R = n+1
2、mid=(L+R)/2
3、query(mid)(树状数组[1,mid]的和)小于q时,L=mid,否则R=mid
4、L+1>=R时,返回 L+1,L+1就是当前未被淘汰的第q个孩子的下标。
那么来考虑这个游戏的过程,一开始的时候第k个孩子被淘汰,然后根据他卡片上的数字 A 判断下一个孩子,卡片上的数字一定不为0。这里我把这个移动分为两步:
1、先在A方向上移动一步到一个当前没有被淘汰的点
2、然后再移动 A - 1步
然后第二步骤移动时,其实是一个关于当前剩余数量的周期运动,如下图所示。
所以我们把可以把移动的过程优化一下,假设第x个孩子被淘汰,第x个孩子的卡片上数字是A,第x个孩子被淘汰以后,剩余孩子的数量是len
1、先在A方向上移动一步到一个当前没有被淘汰的点
2、然后再移动 (A - 1)% len 步
然后这样的话,就变得简单许多了,我们先利用树状前[1,x]项的和找到下标 x 在被淘汰前在孩子们中的顺序y,之后update(x,-1)代表x被淘汰,同时记录剩余孩子的数量为len,
假设是A是朝着数组下标缩小的方向(题目中的右)
记录方向之后,把A变成正数,便于计算。
1、被淘汰的孩子位置在y,先挪一步,到 y-1,判断y-1是否大于 (A-1)%len ,如果是,那么下一个被淘汰孩子就是 y - 1 - ((A-1)%len),如下图所示。
2、如果y-1小于等于 (A-1)%len,那么下一个被淘汰的孩子就是 y - 1 - ((A-1)%len) + len,我给出了2个案例,如下两张图所示。
这样就将A向着数组下标缩小方向的所有情况都考虑到了
接下来继续考虑A向着数组下标放大的方向(题目中的左,实际其实是右)
依旧设本次被淘汰的元素在被淘汰前的位置作为y,淘汰掉y之后剩余孩子的数量为len,y手里的数字为A。
1、首先考虑y加上(A-1)%len小于等于len的情况,这种情况下,下一个被淘汰的位置为 y + ((A-1)%len),如下图
2、接下来,再来考虑y加上(A-1)%len大于len的情况,这种情况下,可以画图看出下一个被淘汰的位置为y+((A-1)%len) - len,我给出了两个案例,如下两张图所示。
这样就把所有的4种情况考虑完了,知道当前被淘汰的元素下标k后,可知A,也可以通过树状数组计算出它在队伍中的位置y,然后更新树状数组k的位置为-1,剩余长度len自减1,之后通过位置y、偏移A、队伍长度len和上文中的4个if,求出下个被淘汰的孩子在队伍中的位置,然后根据位置对树状数组进行二分,求出下标,更新k为这个下标,继续下一次的循环,这样循环n次,第 i 循环开始时对应的k,就是第i个被淘汰的孩子,这样就可以知道每个孩子被淘汰的顺序了。
之后输出上文中 第optOrder个被淘汰的孩子的名字,和optOrder对应的F值即可。
总结下吧,像这种情况比较多的问题,最好是画下图,我们不需要背下这4个if,只需要能够记得是4种,然后画个图,一个一个找出来就可以
三、代码
#include <iostream>
using namespace std;
int n_Tbl[] = {1, 3, 5, 11, 23, 35, 47, 59, 119, 179, 239, 359, 719, 839, 1259, 1679, 2519, 5039, 7559, 10079, 15119, 20159, 25199, 27719, 45359, 50399, 55439, 83159, 110879, 166319, 221759, 277199, 332639, 498959, 500000};
int k_Tbl[] = {1, 2, 4, 6, 12, 24, 36, 48, 60, 120, 180, 240, 360, 720, 840, 1260, 1680, 2520, 5040, 7560, 10080, 15120, 20160, 25200, 27720, 45360, 50400, 55440, 83160, 110880, 166320, 221760, 277200, 332640, 498960};
int f_Tbl[] = {1, 2, 3, 4, 6, 8, 9, 10, 12, 16, 18, 20, 24, 30, 32, 36, 40, 48, 60, 64, 72, 80, 84, 90, 96, 100, 108, 120, 128, 144, 160, 168, 180, 192, 200};
int n_, n, bit[524298], card[500009], order[500009], k;
char name[500009][50];
int optFOrder()
{for (int i = 0; i < 35; i++){if (n_ <= n_Tbl[i]){return k_Tbl[i];}}return -1;
}
int f(int num)
{for (int i = 0; i < 35; i++){if (num <= n_Tbl[i]){return f_Tbl[i];}}return -1;
}
void input()
{for (int i = 1; i <= n_; i++){scanf("\n%s %d", &name[i], &card[i]);}
}
void init()
{n = 1;while (n < n_){n = n * 2;}for (int i = 0; i <= n; i++){bit[i] = 0;}
}
void update(int r, int v)
{if (r <= 0){return;}for (int i = r; i <= n; i = i + (i & (-i))){bit[i] = bit[i] + v;}
}
int query(int r)
{int sum = 0;for (int i = r; i > 0; i = i - (i & (-i))){sum = sum + bit[i];}return sum;
}
void push()
{for (int i = 1; i <= n_; i++){update(i, 1);}
}
int binarySearch(int num)
{int l = 0, r = n + 1;while (l + 1 < r){int mid = (l + r) / 2;if (query(mid) < num){l = mid;}else{r = mid;}}return (l + 1);
}
int absVal(int num)
{if (num < 0){return num * (-1);}else{return num;}
}
void solve()
{int len = n_;for (int i = 1; i <= n_; i++){order[i] = k;if (i == n_){break;}len--;int currentOrder = query(k);update(k, -1);bool left = (card[k] < 0);card[k] = absVal(card[k]);// 默认先挪动一步,挪动一步之后就是len下的周期运动card[k]--;card[k] = card[k] % len;if (left && ((currentOrder - 1) > card[k])){k = currentOrder - 1 - card[k];}else if (left && ((currentOrder - 1) <= card[k])){k = currentOrder - 1 - card[k] + len;}else if (!left && (currentOrder + card[k]) <= len){k = currentOrder + card[k];}else if (!left && (currentOrder + card[k]) > len){k = currentOrder + card[k] - len;}k = binarySearch(k);}
}
int main()
{while (~scanf("%d%d", &n_, &k)){input();init();push();solve();printf("%s %d\n", name[order[optFOrder()]], f(n_));}return 0;
}
相关文章:
POJ 2886 Who Gets the Most Candies? 树状数组+二分
一、题目大意 我们有N个孩子,每个人带着一张卡片,一起顺时针围成一个圈来玩游戏,第一回合时,第k个孩子被淘汰,然后他说出他卡片上的数字A,如果A是一个正数,那么下一个回合他左边的第A个孩子被淘…...
阿里云服务器镜像系统Anolis OS龙蜥详细介绍
阿里云服务器Anolis OS镜像系统由龙蜥OpenAnolis社区推出,Anolis OS是CentOS 8 100%兼容替代版本,Anolis OS是完全开源、中立、开放的Linux发行版,具备企业级的稳定性、高性能、安全性和可靠性。目前阿里云服务器ECS可选的Anolis OS镜像系统版…...
数学建模Matlab之基础操作
作者由于后续课程也要学习Matlab,并且之前也进行了一些数学建模的练习(虽然是论文手),所以花了几天零碎时间学习Matlab的基础操作,特此整理。 基本运算 a55 %加法,同理减法 b2^3 %立方 c5*2 %乘法 x 1; …...
[计算机入门] Windows附件程序介绍(工具类)
3.14 Windows附件程序介绍(工具类) 3.14.1 计算器 Windows系统中的计算器是一个内置的应用程序,提供了基本的数学计算功能。它被设计为一个方便、易于使用的工具,可以满足用户日常生活和工作中的基本计算需求。 以下是计算器程序的主要功能:…...
队列(循环数组队列,用队列实现栈,用栈实现队列)
基础知识 队列(Queue):先进先出的数据结果,底层由双向链表实现 入队列:进行插入操作的一端称为队尾出队列:进行删除操作的一端称为对头 常用方法 boolean offer(E e) 入队 E(弹出元素的类型) poll() 出队 peek() 获取队头 int size 获取队列元素个数 boolean isEmpty(…...
卷积神经网络-池化层和激活层
2.池化层 根据特征图上的局部统计信息进行下采样,在保留有用信息的同时减少特征图的大小。和卷积层不同的是,池化层不包含需要学习的参数。最大池化(max-pooling)在一个局部区域选最大值作为输出,而平均池化(average pooling)计算一个局部区…...
API基础————包
什么是包,package实际上就是一个文件夹,便于程序员更好的管理维护自己的代码。它可以使得一个项目结构更加清晰明了。 Java也有20年历史了,这么多年有这么多程序员写了无数行代码,其中有大量重复的,为了更加便捷省时地…...
【C++】一文带你走入vector
文章目录 一、vector的介绍二、vector的常用接口说明2.1 vector的使用2.2 vector iterator的使用2.3 vector空间增长问题2.4 vector 增删查改 三、总结 ヾ(๑╹◡╹)ノ" 人总要为过去的懒惰而付出代价ヾ(๑╹◡╹)ノ" 一、vector的介绍 vector…...
《Secure Analytics-Federated Learning and Secure Aggregation》论文阅读
背景 机器学习模型对数据的分析具有很大的优势,很多敏感数据分布在用户各自的终端。若大规模收集用户的敏感数据具有泄露的风险。 对于安全分析的一般背景就是认为有n方有敏感数据,并且不愿意分享他们的数据,但可以分享聚合计算后的结果。 联…...
十三、Django之添加用户(原始方法实现)
修改urls.py path("user/add/", views.user_add),添加user_add.html {% extends layout.html %} {% block content %}<div class"container"><div class"panel panel-default"><div class"panel-heading"><h3 c…...
Elasticsearch数据操作原理
Elasticsearch 是一个开源的、基于 Lucene 的分布式搜索和分析引擎,设计用于云计算环境中,能够实现实时的、可扩展的搜索、分析和探索全文和结构化数据。它具有高度的可扩展性,可以在短时间内搜索和分析大量数据。 Elasticsearch 不仅仅是一个…...
gitgitHub
在git中复制CtrlInsert、粘贴CtrlShif 一、用户名和邮箱的配置 查看用户名 :git config user.name 查看密码: git config user.password 查看邮箱:git config user.email 查看配置信息: $ git config --list 修改用户名 git co…...
十天学完基础数据结构-第九天(堆(Heap))
堆的基本概念 堆是一种特殊的树形数据结构,通常用于实现优先级队列。堆具有以下两个主要特点: 父节点的值始终大于或等于其子节点的值(最大堆),或者父节点的值始终小于或等于其子节点的值(最小堆ÿ…...
vertx的学习总结7之用kotlin 与vertx搞一个简单的http
这里我就简单的聊几句,如何用vertx web来搞一个web项目的 1、首先先引入几个依赖,这里我就用maven了,这个是kotlinvertx web <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apac…...
golang学习笔记(二):链路追踪
自定义http连接的服务端 package serverimport ("github.com/gin-gonic/gin""go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin""net/http" )type MyServer struct {Server *http.Server }func GetServer() *MyS…...
git提交代码实际操作
1.仓库的代码 2.克隆代码下存在的分支 git clobe https://gitee.com/sadsadasad/big-event-11.git 3.查看当下存在的分支 git branch -a 在很多情况下,我们是要围绕着dev分支进行开发,所以我们可以在开发之前问明白围绕那个分支进行开发。 4.直接拉去dev分支代码 5.如果没在…...
TF坐标变换
ROS小乌龟跟随 5.1 TF坐标变换 Autolabor-ROS机器人入门课程《ROS理论与实践》零基础教程 tf模块:在 ROS 中用于实现不同坐标系之间的点或向量的转换。 在ROS中坐标变换最初对应的是tf,不过在 hydro 版本开始, tf 被弃用,迁移到 tf2,后者更…...
如何进行网络编程和套接字操作?
网络编程是计算机编程中重要的领域之一,它使程序能够在网络上进行数据传输和通信。C语言是一种强大的编程语言,也可以用于网络编程。网络编程通常涉及套接字(Socket)操作,套接字是一种用于网络通信的抽象接口。本文将详…...
在Spark中集成和使用Hudi
本文介绍了在Spark中集成和使用Hudi的功能。使用Spark数据源API(scala和python)和Spark SQL,插入、更新、删除和查询Hudi表的代码片段。 1.安装 Hudi适用于Spark-2.4.3+和Spark 3.x版本。 1.1 Spark 3支持矩阵 Hudi...
力扣第226翻转二叉数 c++三种方法 +注释
题目 226. 翻转二叉树 简单 给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。 示例 1: 输入:root [4,2,7,1,3,6,9] 输出:[4,7,2,9,6,3,1]示例 2: 输入:root [2,1,3] 输出&am…...
React项目部署 - Nginx配置
写在前面:博主是一只经过实战开发历练后投身培训事业的“小山猪”,昵称取自动画片《狮子王》中的“彭彭”,总是以乐观、积极的心态对待周边的事物。本人的技术路线从Java全栈工程师一路奔向大数据开发、数据挖掘领域,如今终有小成…...
【Vue3】定义全局变量和全局函数
// main.ts import { createApp } from vue import App from ./App.vue const app createApp(App)// 解决 ts 报错 type Filter {format<T>(str: T): string } declare module vue {export interface ComponentCustomProperties {$filters: Filter,$myArgs: string} }a…...
【Pandas】Apply自定义行数
文章目录 1. Series的apply方法2. DataFrame的apply方法2.1 针对列使用apply2.2 针对行使用apply Pandas提供了很多数据处理的API,但当提供的API不能满足需求的时候,需要自己编写数据处理函数, 这个时候可以使用apply函数apply函数可以接收一个自定义函数, 可以将DataFrame的行…...
C#,数值计算——完全VEGAS编码的蒙特·卡洛计算方法与源程序
1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// Complete VEGAS Code /// adaptive/recursive Monte Carlo /// </summary> public abstract class VEGAS { const int NDMX 50; const int …...
纯css实现3D鼠标跟随倾斜
老规矩先上图 为什么今天会想起来整这个呢?这是因为和我朋友吵架, 就是关于这个效果的,就是这个 卡片懸停毛玻璃效果, 我朋友认为纯css也能写, 我则坦言他就是在放狗屁,这种跟随鼠标的3D效果要怎么可能能用纯css写, 然后吵着吵着发现,欸,好像真能用css写哦,我以前还写过这种…...
Pandas数据结构
文章目录 1. Series数据结构1.1 Series数据类型创建1.2 Series的常用属性valuesindex/keys()shapeTloc/iloc 1.3 Series的常用方法mean()max()/min()var()/std()value_counts()describe() 1.4 Series运算加/减法乘法 2. DataFrame数据结构2.1 DataFrame数据类型创建2.2 布尔索引…...
systemverilog function的一点小case
关于function的应用无论是在systemverilog还是verilog中都有很广泛的应用,但是一直有一个模糊的概念困扰着我,今天刚好有时间来搞清楚并记录下来。 关于fucntion的返回值的问题: function integer clog2( input logic[255:0] value);for(cl…...
微服务的初步使用
环境说明 jdk1.8 maven3.6.3 mysql8 idea2022 spring cloud2022.0.8 微服务案例的搭建 新建父工程 打开IDEA,File->New ->Project,填写Name(工程名称)和Location(工程存储位置),选…...
【2023年11月第四版教材】第18章《项目绩效域》(合集篇)
第18章《项目绩效域》(合集篇) 1 章节内容2 干系人绩效域2.1 绩效要点2.2 执行效果检查2.3 与其他绩效域的相互作用 3 团队绩效域3.1 绩效要点3.2 与其他绩效域的相互作用3.3 执行效果检查3.4 开发方法和生命周期绩效域 4 绩效要点4.1 与其他绩效域的相互…...
Android 11.0 mt6771新增分区功能实现三
1.前言 在11.0的系统开发中,在对某些特殊模块中关于数据的存储方面等需要新增分区来保存, 所以就需要在系统分区新增分区,接下来就来实现这个功能,看系列三的实现过程 2.mt6771新增分区功能实现三的核心类 build/make/tools/releasetools/common.py device/mediatek/mt6…...
国外作品集网站/百度seo推广软件
MaxMSP是一款可视化编程语言,它让你不用写代码就可以创建复杂的交互程序。创意编程是在创造性的活动中学习电脑程序设计,充分利用电脑程序构建虚拟世界,在充分地启发和引导下,在解决问题的过程中,主动探索式的学习创意…...
口红机网站怎么做的/网络推广引流是做什么工作
$2016$长城信息杯中国大学生程序设计竞赛中南邀请赛$G$题 前缀和。 把公式化开来,会发现只要求一段区间的和以及一段区间的平方和就可以了。 #pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #…...
web网站开发程序员招聘/企业网站的优化建议
互联网摸鱼日报(2023-04-05) InfoQ 热门话题 阿里云云原生网关 Higress 最佳实践 |InfoQ《公开课》 一把手挂帅、管理层“换血”、警惕大而全…汽车零部件企业如何蹚出数字化路径 Serverless时代,如何应对不确定性?…...
顺德做外贸网站/微信广告投放收费标准
1:打开Apache安装目录下httpd.conf,搜索“LoadModule rewrite_modulemodules/mod_rewrite.so”,找到这一行,去掉前面的“#”;2:找到“AllowOverride None”改为“AllowOverride All” 有两个地方需要修改3&…...
大学网站群建设方案/微信营销的方法7种
一、引言 因为RK3328的芯片手册比较庞大,且为英文版,故今天来一起分析下 二、目录结构 目录(在此之详细分析常用模块) part 1 figure index :手册内所有的结构示意图table index:手册内所有的表格描述符notice:注意点System Overview:系统总览 地址映射 System Boot 分…...
wordpress无法上传头像/百度明星人气排行榜
DS3231实时时钟(RTC)驱动 1、DS3231介绍 DS3231 是一款低成本、极其精确的 I2C 实时时钟 (RTC),具有集成的温度补偿晶体振荡器 (TCXO) 和晶体。 该设备包含电池输入,并在设备的主电源中断时保持准确的计时。 DS3231具有如下特性: 高精度 RTC 全面管理所有计时功能实时时…...