欢迎来我的博客看这篇题解

Problem

在两人竞技比赛中,对于任何正整数 \(a\) ,我们定义 \(BO(2 a-1)\) 如下:两名玩家继续竞争,直到其中一人获胜 \(a\) 次,那么他赢得整个比赛。\(BO(2 a-1)\) 最多包含 \(2a-1\) 小局游戏,最少包含 \(a\) 小局游戏。

现在两个人进行一场 DotA2 比赛,使用的是 \(BO(2b-1)\ \texttt{of}\ BO(2a-1)\) 赛制。该赛制由最多 \(2b-1\) 最少 \(b\) 场主要比赛组成,每个主要比赛都是一个 \(BO(2a-1)\),由最多 \(2a-1\) 最少 \(a\) 局次要比赛组成。

假如比赛的结果是预先确定的:有一个长度为 \(n\) 的 \(0-1\) 串 \(T\) ,其中 1 表示 A 获胜,0 表示 B 获胜。A 和 B 的每一局次要游戏结果都从串 \(T\) 中获取。假如从 \(T\) 串的每个位置开始重复获取次要游戏结果,求最后谁赢了?

\(1\le n,a,b\le 10^5\)

Example

7 2 2
1010101

在该样例中,每个主要比赛都是 \(BO3\),也就是 3 局 2 胜制。主要比赛的每个次要比赛也是 \(BO3\)。现在需要看看从这 7 个位置开始获取每场次要比赛的结果,先求得每场主要比赛的结果,再求整场比赛谁获胜。

从第一个位置开始比赛,\(T=1010101|1010101\dots\),次要比赛的结果为 1:2 2:1 0:2 2:1 1:2... 即 \(10101|10101\dots\),主要比赛的结果为 1:2 1:2...,即 \(00\dots\),也就是 A 队将以 2:1获胜,结果为 \(1\)。

从第二个位置开始比赛,\(T=0101011|0101011\dots\),次要比赛的结果为 \(01101|01101\dots\),主要比赛结果为 \(101\dots\) 也就是 A 队将以 2:1 获胜,结果为 \(1\).

继续从第三个位置开始比赛……直到从最后一个位置开始比赛。得到最终结果为 \(1110111\)。

Solution

将问题简化为这样的形式:

将循环串 \(T\) 以如下规则生成新循环串 \(T^\prime\):

将串 \(T\) 展开。按照顺序在 \(T\) 上进行游戏。如果数字 \(0\)(或数字 \(1\))的累计数量等于胜利条件 \(a\) ,则该小局的胜利方为 \(0\)(或 \(1\)),立即结束该小局游戏并开始新局。在这样生成的“胜利0-1串”上重复上述的游戏规则,当某个数字的累计数量等于胜利条件 \(b\),则该大局结束,得到大局的胜利方。

稍微写点模拟代码演示:

for(int x=1;x<=n;x++)
{
int y=x;
int cnt[2]={0,0};
cnt[T[x]]++;
while(1)
{
if(cnt[0]>=a||cnt[1]>=a)// or >=b
{
if(cnt[0]>=b) cout<<0;
else cout<<1;
break;
}
y++;
if(y>n) y-=n;
cnt[T[y]]++;
}
}

这是一个嵌套问题。我们先考虑内层问题。

注意到上述代码中的 y 只会向右循环移动,可以用循环双指针在 \(O(n)\) 时间复杂度内解决内层问题。

我们可以得到:在 \(x\) 处开始进行一个小局,游戏结束时获胜方为谁、结束之后下一个小局从哪里开始进行。

但是从小局的胜利情况推大局的胜利情况就不能用双指针如法炮制了。因为此时面对的不是一个循环串 \(T\),而是一个内向基环树森林,我们需要将每个点作为起点跑双指针,这样会超时的。

考虑倍增。

我们定义 \(jump_{x,k}\) 为从 \(x\) 开始,进行 \(2^k\) 个小局之后,接下来会从何处继续游戏。定义 \(cnt_{x,k,0/1}\) 为从 \(x\) 开始,进行了 \(2^k\) 个小局中,A/B 队获胜的数量。

在上面,我们已经用双指针求出了每一个起点 \(x\) 开始一小局的胜利方(令 \(cnt_{x,0,胜利方}=1\))和下一局的起点 \(jump_{x,0}\)。由此预处理 \(k=1,2,3\dots\) 的情况。

现在对于每个起点 \(x\),我们进行倍增。类似于倍增求 LCA,我们倍增地找到最远的大局结束点 \(y\),使得这之间双方胜利数量都刚好小于 \(b\)。此时,再向后走一步(\(y=jump_{y,0}\))一定会导致这一大局结束,所以接下来的这一小局的获胜方就是从 \(x\) 开始玩一大局的获胜方了。

Code

#define N 100010

int n,a,b;
string s;
int jump[N][31];
LL cnt[N][31][2];
string ans; int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout.precision(10);
int t=1;
// cin>>t;
while(t--)
{
cin>>n>>a>>b;
cin>>s;
int l=0,r=0;
int cnt0[2]={0,0};
cnt0[s[0]-'0']=1;
while(1)
{
if(l>=s.size()) break;
if(cnt0[0]>=a||cnt0[1]>=a)
{
bool win=(cnt0[1]>=a);
cnt[l][0][win]=1;
jump[l][0]=r+1;
cnt0[s[l]-'0']--;
l++;
continue;
}
r++;
if(r>=s.size()) r-=s.size();
cnt0[s[r]-'0']++;
} // for(int i=0;i<s.size();i++) cout<<cnt[i][0][0]<<" "<<cnt[i][0][1]<<endl; for(int k=1;k<=30;k++)
{
for(int i=0;i<s.size();i++)
{
jump[i][k]=jump[jump[i][k-1]][k-1];
cnt[i][k][0]=cnt[i][k-1][0]+cnt[jump[i][k-1]][k-1][0];
cnt[i][k][1]=cnt[i][k-1][1]+cnt[jump[i][k-1]][k-1][1];
}
} for(int i=0;i<s.size();i++)
{
int x=i;
int now[2]={0,0};
for(int k=30;k>=0;k--)
{
if(now[0]+cnt[x][k][0]<b&&now[1]+cnt[x][k][1]<b)
{
now[0]+=cnt[x][k][0];
now[1]+=cnt[x][k][1];
x=jump[x][k];
}
}
ans.push_back(cnt[x][0][1]+'0');
// if(now[0]==b) ans.push_back('0');
// if(now[1]==b) ans.push_back('1');
} cout<<ans<<endl; }
return 0;
}

2024牛客多校3J Rigged Games的更多相关文章

  1. 2019牛客多校第一场 I Points Division(动态规划+线段树)

    2019牛客多校第一场 I Points Division(动态规划+线段树) 传送门:https://ac.nowcoder.com/acm/contest/881/I 题意: 给你n个点,每个点有 ...

  2. 牛客多校第一场 B Inergratiion

    牛客多校第一场 B Inergratiion 传送门:https://ac.nowcoder.com/acm/contest/881/B 题意: 给你一个 [求值为多少 题解: 根据线代的知识 我们可 ...

  3. 2019牛客多校第二场 A Eddy Walker(概率推公式)

    2019牛客多校第二场 A Eddy Walker(概率推公式) 传送门:https://ac.nowcoder.com/acm/contest/882/A 题意: 给你一个长度为n的环,标号从0~n ...

  4. 牛客多校第三场 F Planting Trees

    牛客多校第三场 F Planting Trees 题意: 求矩阵内最大值减最小值大于k的最大子矩阵的面积 题解: 矩阵压缩的技巧 因为对于我们有用的信息只有这个矩阵内的最大值和最小值 所以我们可以将一 ...

  5. 牛客多校第三场 G Removing Stones(分治+线段树)

    牛客多校第三场 G Removing Stones(分治+线段树) 题意: 给你n个数,问你有多少个长度不小于2的连续子序列,使得其中最大元素不大于所有元素和的一半 题解: 分治+线段树 线段树维护最 ...

  6. 牛客多校第四场sequence C (线段树+单调栈)

    牛客多校第四场sequence C (线段树+单调栈) 传送门:https://ac.nowcoder.com/acm/contest/884/C 题意: 求一个$\max {1 \leq l \le ...

  7. 牛客多校第3场 J 思维+树状数组+二分

    牛客多校第3场 J 思维+树状数组+二分 传送门:https://ac.nowcoder.com/acm/contest/883/J 题意: 给你q个询问,和一个队列容量f 询问有两种操作: 0.访问 ...

  8. 2019牛客多校第八场 F题 Flowers 计算几何+线段树

    2019牛客多校第八场 F题 Flowers 先枚举出三角形内部的点D. 下面所说的旋转没有指明逆时针还是顺时针则是指逆时针旋转. 固定内部点的答案的获取 anti(A)anti(A)anti(A)或 ...

  9. 2019年牛客多校第一场B题Integration 数学

    2019年牛客多校第一场B题 Integration 题意 给出一个公式,求值 思路 明显的化简公式题,公式是分母连乘形式,这个时候要想到拆分,那如何拆分母呢,自然是裂项,此时有很多项裂项,我们不妨从 ...

  10. 2020牛客多校第八场K题

    __int128(例题:2020牛客多校第八场K题) 题意: 有n道菜,第i道菜的利润为\(a_i\),且有\(b_i\)盘.你要按照下列要求给顾客上菜. 1.每位顾客至少有一道菜 2.给顾客上菜时, ...

随机推荐

  1. Abaqus Matrix Genrate 分析 | 输出总体刚度

    引言 abaqus 可以输出模型的刚度/质量/阻尼/载荷矩阵等: 输出单元刚度矩阵 输出范围可以是一个单元,也可以是多个单元 输出总体刚度矩阵 输出的数据是整个模型的刚度矩阵,或者是某一特定区域的总体 ...

  2. Anoii之UDP与多路复用

    代码连接:https://github.com/Afeather2017/anoii/blob/master/src/udp_peer.cc 以往写了TCP的多路复用,发现它还挺难写对的.现在写UDP ...

  3. Url base64加密

    class UrlEncryption { /** * base64编码 * * @param string * @return string */ public static function en ...

  4. 举个栗子之gorpc - 消息的编码和解码

    2022年的第一个rpc,比以往来的更早一些... 留杭过年...写点东西 初始化项目gorpc 借助go module我们可以轻易创建一个新的项目 mkdir gorpc go mod init g ...

  5. TMS WEB Core的DEMO

    TMS WEB Core的思路就是把你界面设计转换成js.这个打通了,将会使生产效率呈几何级数提高. 说如何让其demo的能跑起来: 1.看图.增加参数(TMSHttpConfig.exe). 2.运 ...

  6. 前端ai工具v0使用配置

    资料 ai工具Vo Installation - Tailwind CSS 以vue3 + sass为例,配置如下 安装tailwindcss npm install -D tailwindcss n ...

  7. nginx配置代理指向Redis

    stream { upstream redis { server 127.0.0.1:6379 max_fails=3 fail_timeout=30s; #*redis-addres*替换为真实地址 ...

  8. eolinker返回值正则处理后设置为全局变量

    特别注意:需要使用全局变量前务必阅读本链接https://www.cnblogs.com/becks/p/13713278.html 如下图,返回值content内,需要取出验证码后面的数字 预处理, ...

  9. MySQL 中的 MVCC 是什么?

    MySQL 中的 MVCC 是什么? MVCC(Multi-Version Concurrency Control) 是 MySQL 数据库用来处理并发访问的技术,特别是在 InnoDB 存储引擎中, ...

  10. kettle介绍-Step之加密及解密

    加密 进入kettle的安装目录 cd /d D:\Application\pdi-ce-6.0.0.0-353\data-integration windows系统命令行执行:Encr.bat -k ...