题解|2023暑期杭电多校07

【原文链接】

1002.Random Nim Game

诈骗博弈题

题目大意

Nim是一种双人数学策略游戏,玩家轮流从不同的堆中移除棋子。在每一轮游戏中,玩家必须至少取出一个棋子,并且可以取出任意数量的棋子,条件是这些棋子都来自同一个棋子堆。走最后一步棋(即取出最后一块棋子)的人获胜。

现在更改游戏规则,在每个回合中,棋手必须选择一个棋子堆。假设他选择的堆包含 x x x 个棋子,将从 [ 1 , x ] [1,x] [1,x] 中随机一个整数 y y y ,并从堆中移除 y y y 个棋子

求先手获胜的概率,答案取模

解题思路

看起来很吓人的一道题(谁被吓退了我不说)//

考虑只有一个堆的情况
若只有 1 1 1 个棋子,先手必胜
如果有 2 2 2 个棋子,有 1 2 \dfrac{1}{2} 21 的概率拿完获胜,有 1 2 \dfrac{1}{2} 21 的概率余 1 1 1 失败,综合胜率 1 2 \dfrac{1}{2} 21
⋮ \vdots
如果有 x   ( x > 1 ) x\ (x>1) x (x>1) 个棋子,有 n − 2 n \dfrac{n-2}{n} nn2 的概率转移到 剩余个数 > 1 >1 >1 的状态,有 1 n \dfrac{1}{n} n1 的概率拿完获胜,有 1 n \dfrac{1}{n} n1 的概率余 1 1 1 失败。递归得到 x > 1 x>1 x>1 的状态下的综合胜率为 1 2 \dfrac{1}{2} 21

再考虑多堆的情况
如果所有堆的棋子数量均为 1 1 1 ,则当堆数 n n n 为奇数时先手必胜
如果有某堆的数量多于 1 1 1 个,那么必胜态将以 1 2 \dfrac{1}{2} 21 的概率流转

综上所述,如果所有堆的棋子数量均为 1 1 1 ,则当堆数 n n n 为奇数时先手必胜, n n n 为偶数时先手必败,其余情况综合胜率 1 2 \dfrac{1}{2} 21

参考代码

void solve()
{
    ll n;cin >> n;ll mx=0,t;
    FORLL(i,1,n){
        cin >> t;
        mx=max(mx,t);
    }if(mx>1) cout << inv(2) << endl;
    else if(n%2) cout << 1 << endl;
    else cout << 0 << endl;
}

1004.Medians Strike Back

构造

题目大意

定义长度为 n n n 的整数序列的中位数:

  1. 如果 n n n 为奇数,则中位数是将序列排序后正中间的数
  2. 如果 n n n 为偶数,则中位数是将序列排序后中间两个数中,出现次数较多的那个数,如果出现次数相同则取较小的那个数

定义序列的 s h i k n e s s shikness shikness :该序列中位数出现的次数
定义序列的 n i t n e s s nitness nitness :该序列的所有连续子串的 s h i k n e s s shikness shikness 的最大值

给定一个正整数 n n n ,构造长度为 n n n 且仅含元素 1 , 2 , 3 1,2,3 1,2,3 的序列,并使 n i t n e s s nitness nitness 最小化,求出最小值

解题思路

构造找规律
n i t n e s s m i n = 1 nitness_{min}=1 nitnessmin=1 时,构造出最长序列为: 123 123 123
n i t n e s s m i n = 2 nitness_{min}=2 nitnessmin=2 时,构造出最长序列为: 1313221313 1313221313 1313221313
n i t n e s s m i n = 3 nitness_{min}=3 nitnessmin=3 时,构造出最长序列为: 131313222131313 131313222131313 131313222131313
n i t n e s s m i n = 4 nitness_{min}=4 nitnessmin=4 时,构造出最长序列为: 1313131322131313132213131313 1313131322131313132213131313 1313131322131313132213131313

如果序列中存在两个及以上的 2 2 2 ,那么 2 2 2 是稳定作为中位数的,因此可以考虑以下构造方法:
连续 n n n 13 13 13 为一个单位子串//每个单位子串利用两个或三个连续的 2 2 2 隔开,将得到以下格式的序列: 1313 ( n 对 ) ⋯ 22   1313 ( n 对 ) ⋯ 22   1313 ( n 对 ) 1313(n对)\cdots22\ 1313(n对)\cdots22\ 1313(n对) 1313(n)22 1313(n)22 1313(n)

下面阐释这种构造方法的合法性

  1. 对于整个序列, n i t n e s s = c n t 2 = n nitness=cnt_2=n nitness=cnt2=n
  2. 对于含多个 2 2 2 的子串, 2 2 2 稳定做中位数, n i t n e s s < c n t 2 = n nitness<cnt_2=n nitness<cnt2=n
  3. 对于仅含一个 2 2 2 的子串,这个 2 2 2 一定在单位子串的左边或右边,而单位子串的长度为 2 n 2n 2n ,因此加上 2 2 2 后的长度为奇数, 2 2 2 稳定做中位数, n i t n e s s = 1 nitness=1 nitness=1
  4. 对于不含 2 2 2 的子串,其一定也是单位子串的子串,而单位子串中 c n t 1 = c n t 3 = n cnt_1=cnt3=n cnt1=cnt3=n ,因此 n i t n e s s ≤ n nitness\le n nitnessn

计数得到最长长度的通项公式: l e n i = 2 i ( ⌊ i 2 ⌋ + 1 ) + i len_i=2i(\lfloor \dfrac{i}{2} \rfloor+1)+i leni=2i(⌊2i+1)+i

初始化长度数组,二分查找即可

参考代码

#define N 500000
vector<ll> v(N);
void solve()
{
    ll n;cin >> n;
    cout << lower_bound(ALL(v),n)-v.begin() << endl;
}
/*----------Initialize----------*/
    v[0]=0;
    FORLL(i,1,N){
        v[i]=(i/2+1)*2*i+i;
        if(v[i]>1e11) break;
    }v.shrink_to_fit();
/*----------Initialize----------*/

1011.Three Operations

签到题

题目大意

给定正整数 x , a , b x,a,b x,a,b 可以进行以下操作:

  1. x ← x − 1 x\leftarrow x-1 xx1
  2. x ← ⌊ x + a 2 ⌋ x\leftarrow \lfloor \dfrac{x+a}{2} \rfloor x2x+a
  3. x ← ⌊ x + b ⌋ x\leftarrow \lfloor \sqrt{x+b} \rfloor xx+b

求使得 x x x 变为 0 0 0 的最少操作次数

解题思路

每次比较三种操作后的 x x x 最小即可

参考代码

void solve()
{
    ll x,a,b,t,re=0;cin >> x >> a >> b;
    while(x){
        t=min((x+a)/2,(ll)sqrt(x+b));
        if(t<x-1) {re++;x=t;}
        else {re+=x;break;}
    }cout << re << endl;
}

1013.Minimal and Maximal XOR Sum

归并排序、贪心

题目大意

给定一个长度为 n n n 的排列 p p p ,每次操作可以选定一段连续子序列 p i , j p_{i,j} pi,j ,花费等同于元素个数的代价 c = j − i + 1 c=j-i+1 c=ji+1 ,使得这一段顺序反转
记使得排序变成自然排序( p i = i p_i=i pi=i )所经过的一系列操作中,每一次的代价的异或和为 x = c 1 ⊕ c 2 ⊕ ⋯ ⊕ c i x=c_1 \oplus c_2 \oplus \cdots \oplus c_i x=c1c2ci
x x x 的最大值和最小值

解题思路

排列的奇偶性定义为其所具有的逆序对数的奇偶性。任意一个n阶排列,可经过一系列对换转变为标准排列,且所做对换的次数与排列具有相同的奇偶性。

观察操作的特点可以得出,选定单一元素操作时,排列本身不发生改变,但产生 1 1 1 点代价//这意味着所得结果 x x x 的最后一个二进制位可以任意调整(和 1 1 1 做异或)

考虑使得 x x x 最小的操作方法
每次花费 2 2 2 代价做对换,最小值 x m i n x_{min} xmin 一定会落在 0 0 0 2 2 2 上。根据对换次数与排列奇偶性的关系,判断排列逆序对数的奇偶性即可,可以使用归并排序进行逆序对计数

接下来考虑使得 x x x 最大的操作方法
在排列 p p p 已经有序的情况下,考虑如何操作花费代价可以使得异或和 x x x 产生高位 1 1 1 :先花费高代价 c c c 反转某个长子序列,再连续花费 2 2 2 代价做对换将序列恢复为有序

可以发现 x x x 的最大可能二进制位数与 n n n 相同,逐位考虑转 1 1 1 记某位上的权重为 2 m < n 2^m <n 2m<n ,则反转 2 m 2^m 2m 个数后,恢复有序需要连续做对换的次数为 2 m ( 2 m − 1 ) / 2 2^m(2^m-1)/2 2m(2m1)/2 m ≥ 2 m\ge 2 m2 时对换次数为偶数,即对最终的异或和 x x x 无影响,这意味着按照上述策略可以将 x x x 倒数第3位(权重为4)及以前的数位全部置1//

m = 1 m=1 m=1 时对换次数为 1 1 1 ,和反转 2 1 2^1 21 个数的代价 2 2 2 抵消,因此无法变更倒数第二位的值

综上所述,只需将 x x x 调整为与 n n n 具有相同二进制数的最大值,再判断倒数第二位即可//

时间复杂度

归并排序: O ( n log ⁡ n ) O(n\log n) O(nlogn)

参考代码

void solve()
{
    ll n;cin >> n;ll mn,mx;
    vector<ll> v(n);
    for(auto &x:v) cin >> x;
    ll cntinv=mergeSortAndCount(v,0,n-1);
    if(cntinv%2) mn=2;else mn=0;
    ll t=n,dig=0;while(t) {dig++;t/=2;}
    mx=(1<<dig)-1;
    if(mn==0) mx-=2;
    if(n==1) cout << "0 1" << endl;
    else cout << mn << ' ' << mx << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深翼CCLMSY

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值