首页 > 其他分享 >YACS 2022年8月月赛 甲组 T1 约瑟夫问题 题解

YACS 2022年8月月赛 甲组 T1 约瑟夫问题 题解

时间:2023-05-11 21:03:28浏览次数:42  
标签:二分 YACS loc int 题解 位置 出局 甲组 now

又来填坑了(大雾

题目链接

#1.为什么用树状数组

做多了题目,看一眼这题就知道要用数据结构了,进一步分析就可以知道这是一道二分和树状数组的题目。(其实用变形的链表 $n\sqrt{n}$ 卡卡常也可以吧)

# 2.具体思路

首先设定 $n$ 个位置,第 $i$ 个位置为 $1$ 代表这个人还没出局,否则代表出局了。很容易发现求 $l$ 到 $r$ 中没出局的人数量就是 $l$ 到 $r$ 的和了。

这样,设当前在第 $now$ 个人,跳过 $x$ 个人后的那个人出局,就相当于找 $now$ 的后面(包括 $now$)的第 $x + 1$ 个为 $1$ 的数字。

# 3.how to do it?

确定完正确思路后,来看怎么求。

这是这道题的关键,我们需要使用  二分  算法,(我这里用的是倍增,更加好写)。

首先看要出局的人在什么位置,因为有可能跨越一个环。

如果 $now$ 到 $n$ 中没出局的人数 $\geq x$,那么答案在 $now$ 到 $n$ 中。否则,$x$ 要减去 $now$ 到 $n$ 的人数,之后就转换成了求 $1$ 到 $now-1$ 第 $x$ 个为 $1$ 的人了。(类似线段树上二分的思想)

当锁定了答案范围之后,现在来讨论如何二分。取 $mid=l+r>>1$,这里如果就按照想的二分,码量会大一点点。

我们可以转换成二分最后一个位置 $loc$,使得 $l$ 到 $loc$ 中没出局的人个数是 $x-1$,那么 $loc+1$ 一定没出局。(否则 $loc+1$ 就是最后一个了啊)我们要求的就是 $loc+1$ 了,这样二分就会简单很多了。(类似倍增求 $LCA$ 的思想)

另外,每次二分完别忘了在这个位置加上 $-1$(出局了),以及更新 $now$ 的值,这题还是环状的,需要取模还有一大堆细节请见代码。

然后就能愉快地 AC 神仙分块甲组题了。

# 4.闲话(其他做法)

其实我也口胡了一个线段树上二分的做法,但是胡完感觉有点困难,$n\log^2 n$ 能过就没写其实。

大概是这样的:这里的线段树二分不是普通的线段树二分,还需要一个备用量 $sum$。如果二分的时候走了右端点那么需要加 $sum$,其实还有一大堆的分类讨论,所以就没写。

关于变形的链表,每个位置不仅存储下一个元素的位置,还会存储下 $\sqrt{n}$ 个元素的位置,这样就可以做到 $n\sqrt{n}$,也是一个不错的解法。

 

代码很短,压了点行:

#include <iostream>
using namespace std;
int n, now = 1;
int a[500005], c[500005];
void add (int x, int y) {for (; x <= n; x += x & -x) c[x] += y;}
int query (int x) {return x == 0 ? 0 : c[x] + query (x - (x & -x) );}
int sum (int x, int y) {return query (y) - query (x - 1);}
int q (int x) {//求 now(包含)后面第 x 个不为 0 的。
    int l = 1, r = n, res = sum (now, n);
    if (res >= x) {
        l = now;
        r = n;
    } else {
        x -= res;
        l = 1, r = now - 1;
    }
    int ret = l - 1;
    for (int i = 19; i >= 0; i --)
        if (ret + (1 << i) <= n && sum (l, ret + (1 << i) ) < x) ret += 1 << i;
    return ret + 1;
}
int main () {
    scanf ("%d", &n);
    for (int i = 1; i <= n; i ++) {
        scanf ("%d", &a[i]);
        ++ a[i];
        a[i] %= (n - i + 1);
        add (i, 1);
    }
    for (int i = 1; i <= n; i ++) {
        if (a[i] == 0) a[i] += n - i + 1;
        int x = q (a[i]);
        printf ("%d\n", x);
        add (x, -1);
        now = q (a[i]);
    }
    return 0;
}

 

标签:二分,YACS,loc,int,题解,位置,出局,甲组,now
From: https://www.cnblogs.com/Xy-top/p/17392216.html

相关文章

  • agc029c 题解
    首先随便想个暴力,对于\(a_i>a_{i-1}\),我们直接往字符串的末尾加上一些最小的字符。对于\(a_i\lea_{i-1}\),我们保留前缀之后随便加一个位置的\(1\)。发现这个随便的位置不是很好找,于是想到用二分转枚举为判断。二分最大的字符(可以转化为数字)\(x\),每次我们只往最后一......
  • 51nod 1227 平均最小公倍数 题解
    题目大意\[A(n)=\frac{1}{n}\sum_{i=1}^{n}\text{lcm}(n,i)\\F(a,b)=\sum_{i=a}^{b}A(i)\\\]给定\(a,b\),求\(F(a,b)\mod10^9+7\)。\(1\lea\leb\le10^9\)。思路首先我们可以想到,如果我们定义\(B(n)=\underset{i=1}{\overset{n}{\sum}}A(i)\),那么\(F(a,......
  • 【题解】P4331 [BalticOI 2004]Sequence 数字序列
    以各种方式出现被玩烂的题目,算是小trick题?cpeditor意外地好用思路可并堆。平行时空同位体:CF13CP4331P4597CF713CP2893已知做法:\(O(n^2)\)dp:令\(f[i][j]\)为前\(i\)个数不超过\(j\)的最小代价优化:使用堆维护dp产生的折线(P4597题解区)\(O(n\logn......
  • AtCoder Beginner Contest 298 题解
    题面:https://atcoder.jp/contests/abc298/tasks_printA-JobInterview直接模拟即可。#include<bits/stdc++.h>#include<ext/pb_ds/assoc_container.hpp>#include<ext/pb_ds/tree_policy.hpp>#include<ext/pb_ds/hash_policy.hpp>usingnamespace......
  • # Codeforces Round 872 (Div. 2) 题解
    CodeforcesRound872(Div.2)题解A.LuoTianyiandthePalindromeString略B.LuoTianyiandtheTable略C.LuoTianyiandtheShow略D1.LuoTianyiandtheFloatingIslands(EasyVersion)题意在树上随机撒\(k(k\leq3)\)个关键点,规定一个点是好的当且仅当这个......
  • springboot跨域问题解决方案
    以下内容仅供自己学习使用,侵权私聊必删。在进行前后端交互的时候,往往会遇到以下的跨域问题。那么解决这种跨域的话,可以使用以下这种方法:(引自于程序员青戈)创建config配置目录新建CorsConfig类然后把下面的内容复制进去根据自己需要修改以下就可以解决跨域问题啦importo......
  • P1676 [USACO05FEB] Aggressive cows G 题解
    题目传送门解题思路最大值最小化问题,考虑二分答案。首先要排序,保证序列单调不降,然后求出两个隔间之间的距离。sort(a+1,a+1+n);for(rii=1;i<=n;i++) dis[i]=a[i+1]-a[i];二分出一个\(mid\),判断它是否合法:每次累加距离,如果距离和比\(mid\)大,说明当前可以分配牛,记录数量......
  • Codeforces Round 683 (Div. 1, by Meet IT) ABCDF题解
    F和D都在ABC上做过类似的,但是没打好,道心破碎。。。。A.Knapsack若物品质量在[(w+1)/2,w]之间做完了否则一直贪心加voidsolve(){intn;llw;cin>>n>>w;intc=n;for(inti=1;i<=n;i++){cin>>a[i];if(a[i]>w)c--;}if(!c){......
  • Linux环境下,输入文件的编码格式和系统格式导致的问题解决办法
    1.用vim111.txt进入查看状态 2系统格式的查看和修改查看指令:setfileformat修改指令:setfileformat=unix3编码格式的查看和修改 查看指令 :setfileencoding 修改指令 在Vim中直接实行转换文件编码,比如将一个文件转换成u......
  • linux静态库的制作及问题解决
       首先介绍下分文件,在学习或者开发中,实现一个项目需要实现很多的功能,那么这些功能不可能在一个".c"文件下实现,需要多个".c"文件来共同实现,但是程序的入口只有一个,就体现了分文件编程的重要性,在主函数中调用其余的功能函数。分文件编程的优点及意义就是:分模块编程思......