首页 > 其他分享 >noi.ac775题解

noi.ac775题解

时间:2024-10-21 21:32:44浏览次数:7  
标签:noi ac775 int 题解 ll mid len rr 单调

Gameb

文件 OI : gameb

时限 : 1000ms

空间 : 512MiB

Alice 和 Bob 正在玩一个游戏。

具体来说,这个游戏是这样的,给定一个数列,从 Alice 开始,两个人轮流操作,每次操作可以从数列的头部或者尾部删去一个数字,当这个数列满足一定条件的时候,最后一次操作的人获胜。如果一开始就满足条件,则认为 Bob 获胜。

条件有的时候是单调不下降有的时候是单调,这会变化。

现在有一个长度为 \(n\) 的数列,两个人在上面玩了 \(m\) 次游戏,每次他们选定一个区间 \(l,r\) 作为游戏的场地。他们想知道如果两个人都采用最优策略,那么谁会获得胜利。

输入格式

第一行两个整数,第一个整数 \(n\) 表示序列的长度,第二个整数 \(type\),如果为 \(1\) 则表示胜利条件是单调不下降,如果为 \(2\) 则是单调。

接下来一行 \(n\) 个整数,第 \(i\) 个整数表示 \(a_i\)。

接下来一个整数 \(m\),表示游戏次数。

接下来 \(m\) 行,每行两个整数 \(l_i,r_i\) 表示区间。

输出格式

一共 \(m\) 行,每行一个字符串,如果 Alice 必胜则输出“Alice”,否则输出“Bob”。

样例数据

输入样例一

4 2
1 5 3 4
3
1 2
1 3
1 4

输出样例一

Bob
Alice
Bob

数据规模与约定

本题采用捆绑测试

对于 20 分的数据,\(n,m\le 5\);

对于 40 分的数据,\(n,m\le 1000\);

对于另外 30 分的数据,\(type=1\);

对于所有数据,满足 \(3\le n,m≤10^6,0≤a_i≤10^9,1≤l_i≤r_i≤n\)。

时间限制:\(1s\)

空间限制:512MB


正解

首先求一下每个点出发的单调序列长度

	for(int i=n,p=n;i;i--){
        if(st[i+1]<st[i]) p=i;
        b[i]=p;
    }
    if(ty==2){for(int i=n,p=n;i;i--){
        if(st[i+1]>st[i]) p=i;
        b[i]=max(b[i],p);
    }}

我们把一个游戏看成在二维平面上玩,一开始在\((0,0)\)

每次删掉开头,我们认为是从\((x,y)\)走到\((x+1,y)\),删掉尾部是从 \((x,y)\)
走到\((x,y+ 1)\)。

那么假如左边删个,右边删\(y\)个,那么\(SG(x,y)=0\),我们称之为终止态,那么和终止态相邻且不
为终止态的点\(SG = 1\),称其为边界态。

不难发现对于一个\(x\),终止态只有一个,而且随着\(x\)增大\(y\)是单调不降的,每次向上向右走
还有两个小结论:

  1. 假设\((x + 1,y+ 1)\)必败,那么\((x,y)\)必败

  2. 假设\((x + 1,y+ 1)\),\((x + 2,y+ 2)\)都必胜,那么\((x,y)\)必胜

考虑第二个结论的证明

这里的\((x + 2,y + 2)\)必胜是保证\((x,y+ 2)\),\((x + 1,y+ 2)\),\((x+2,y+ 1)\),\((x +2,y)\)均不为终止态。
因为\((x + 1,y+ 1)\)必胜则\((x + 2,y+ 1)\),\((x +1,y+2)\)中有一个必败。

假设是\((x+1,y+1)\)必败,那么\((x+ 2,y)\)必胜,又因为\((x + 1,y+ 1)\)必胜,那么\((x + 1,y)\)必败,那么\((x,y)\)就必胜了。
另一种假设同理。

这里再加入另一种解释方式:

我们考虑现实博弈情景

设区间 \([l,r]\) 中的最长单调段的长度为 \(len\)。

\(len=r−l+1\),即 \([ l , r ]\) 本身是单调段,先手必败;
\(len=r−l\),根据上条可得这种情况先手必胜;
\(len=r−l−1\),这里又分为 \([ l , r − 2 ]\) 是单调段、\([ l + 1 , r − 1 ]\) 是单调段、\([ l + 2 , r ]\) 是单调段三种情况:

  1. 若 \([ l , r − 2 ]\)是单调段,那么正常情况下大家都不会拿最后一个,不然对面再拿掉倒数第二个就 gg ,因此都是从左往右拿,直到剩下的是个单调段为止。那么就可以预处理 \(L_i\)

表示以 \(i\) 为右端点的最长单调段到哪,这样就可以算出步数,根据奇偶性算出先手的胜负;

tips: \(1,2,3,4,4,4,2,3\),当拿剩\(4,4,4,2,3\) 的时候,先手直接拿掉最后一个,获胜

  1. \([ l + 2 , r ]\) 是单调段的情况同理;

  2. 若 \([ l + 1 , r − 1 ]\) 是单调段,先手后手一前一后完事,先手必败。

所以问题等价于询问从(0,0)开始,一路向右上走到最大点的那个点的状态。

那么考虑\((0,0),(1,1),...,(m,m)\)这条对角线上(\((m,m)\)是终止态或者边界态),那么只有三种
可能:

  1. 全为必胜;
  2. 全为必败;
  3. (m,m)为边界态必胜,其余必败。

那我们只要预处理\(b_1\)表示左端点为\(i\),最长的单调区间的右端点的位置(也就是终止态)(也就是\(i\)开始向右延伸最长多长是合法的)
\(c_i = max(b_{i+1},b_i+1)\)也就是边界态。

询问那个的状态,只要看从那个点走到边界态的奇偶性就行了,注意不能看走到终止态的奇偶性

就不难二分出m。

如何二分???假如(m,m)是终止态就是情况2,否则双方要么一直删左边,要么一直删右边,只要再二分一下两种情况走到边界态的长度,然后判一下奇偶性(全奇必败,有偶必胜)即可。

		while(L<R){
            int len=(L+R)>>1;
            if(c[l+len]>=r-len) R=len;
            else L=len+1;
        }
        l+=L-1;r-=L-1;
        L=0;R=r-l+1;
        while(L<R){
            int len=(L+R)>>1;
            if(c[l+len]>=r) R=len;
            else L=len+1;
        }
        u=L;
        L=0;R=r-l+1;
        while(L<R){
            int len=(L+R)>>1;
            if(c[l]>=r-len) R=len;
            else L=len+1;
        }

正解二

另一种解法(没想到吧):

考虑\(sg\)函数的动态规划转移

设\(f[l][r]\)为区间\(l,r\)中是否先手必胜

那么我们很容易推出这个逻辑式:\(f[l][r]=\lnot f[l][r-1] \lor \lnot f[l+1][r]\)

那么我们再把这段抠过来:

设区间 \([l,r]\) 中的最长单调段的长度为 \(len\)。

\(len=r−l+1\),即 \([ l , r ]\) 本身是单调段,先手必败;
\(len=r−l\),根据上条可得这种情况先手必胜;
\(len=r−l−1\),这里又.......(自己上去看)

所以我们列出了这个暴力的转移式:

\[\begin{align*} f[l][r]& = \lnot f[l][r−1]\lor \lnot f[l+1][r]\\ & =(f[l][r−2]\lor f[l+1][r−1])\lor (f[l+1][r−1]∧f[l+2][r]) \end{align*} \]

那么, \(f [l + 1][r − 1] = 0\) 也就是 \(f [l ][ r] = 0\)

若 \(f[l + 1][r − 1] = 1\),则一定有 \(f [l + 1][r − 2] = 0\)或 $f[l + 2] [r − 1] = 0 $,

这两个东西非常amzing啊,前者会导致 $f[l][r − 2] = 1 $ ,后者会导致$ f [l + 2 ][r ]= 1$

两者代入转移式都会使 \(f [l][r] = 1\) 因此 $ f[l][r]=f[l+1][r-1] $

那么这玩意和上面格路转移有什么区别???

所以我们考虑将这个询问序列向内缩

求出\(mid=(l+r)/2\)所在的一个单调区间,这既是答案


全部代码

TAGS

	#include
// #include"../need.cpp"
using namespace std;
// #define int long long 
#define itn int
constexpr int oo = 2000006;
int n,c,st[oo];
pair<int,int> sp[oo],seg[oo];
int cnt,sum;
itn sr[oo],nr[oo],nl[oo];
int tmp[oo],m;
bool cmp(const pair<int,int> &a,const pair<int,int> &b){return a.first<b.first||a.first==b.first&&a.second>b.second;}
int t;
main(void){
    // fre();
    freopen("gameb.in","r",stdin);
    freopen("gameb.out","w",stdout);
    cin.tie(0)->sync_with_stdio(0);
    cin >> n >> c;
    for(int i=1;i<=n;i++) cin >> st[i];
    if (c==1){
        for(int i=n,p=n;i;i--){
            if(st[i+1]<st[i]) p="i;" sr[i]="p;" }="" for(int="" i="1;i<=n;i++)" tmp[i]="max(sr[i+1],sr[i]+1);" cin="">> m;
        int l,r;
        itn ll,rr,u,v;
        while(m--){
            cin >> l >> r;
            ll=0; rr=(r-l+1)/2; 
            if(sr[l]>=r){puts("liulei");continue;}
            if(tmp[l]>=r){puts("se");continue;}
            while(ll<rr){ int="" mid="(ll+rr)">>1;
                if(tmp[l+mid]>=r-mid) rr=mid;
                else ll=mid+1;
            }
            l+=ll-1;r-=ll-1;
            ll=0;rr=r-l+1;
            while(ll<rr){ int="" mid="(ll+rr)">>1;
                if(tmp[l+mid]>=r) rr=mid;
                else ll=mid+1;
            }
            u=ll;
            ll=0;rr=r-l+1;
            while(ll<rr){ int="" mid="(ll+rr)">>1;
                if(tmp[l]>=r-mid) rr=mid;
                else ll=mid+1;
            }
            v=ll;
            if((u&1)&&(v&1)) puts("liulei");
            else puts("se");
        }
        exit(0);
    }
    else {
    int last=1;
    for(int i=2;i<=n;i++) if(st[i-1]>st[i]){
        sp[++cnt]=make_pair(last,i-1);
        last=i;
    }
    sp[++cnt]=make_pair(last,n);
    last=1;
    for(int i=2;i<=n;i++) if (st[i-1]<st[i]){ sp[++cnt]="make_pair(last,i-1);" last="i;" }="" sort(sp+1,sp+1+cnt,cmp);="" for(int="" i="1;i<=cnt;i++)" if="" (sp[i].second="">seg[sum].second){
            for(int j=last;j<=sp[i].first-1;j++)
                nr[j]=seg[sum].second;
        last=sp[i].first;
        seg[++sum]=sp[i];
        sr[sum]=sp[i].second;
    }
    for(int j=last;j<=n;j++) nr[j]=n;
    for(int i=n,j=sum;i>=1;i--){
        if (j&&i==seg[j-1].second) j--;
        nl[i]=seg[j].first;
    }
    cin >> t;
    while (t--){
        int l,r,mid;
        cin >> l >> r;
        mid=(l+r)>>1;
        int ll,rr,x=lower_bound(sr+1,sr+1+sum,(l+r+1)>>1)-sr;
        int even=!((r-l+1)&1);
        int t=min(mid-seg[x].first+even,seg[x].second-mid);
        if (x+1<=sum&&seg[x+1].first<=mid)
            t=max(t,min(mid-seg[x+1].first+even,seg[x+1].second-mid));
        t=min(t,min(mid-l+even,r-mid));
        ll=mid-t+even; rr=mid+t;
        while (l<ll&&rr<r&&(nr[ll-1]>=rr-1||nr[ll+1]>=rr+1)) ll--,rr++;
        if (nr[ll]>=rr)
            puts("liulei");
        else if (nr[ll]==rr-1||nr[ll+1]>=rr)
            puts("se");
        else if (nr[ll]==rr-2)
            puts(((rr-ll+1-(rr-nl[rr-1])-(nr[rr-2]>rr-1))&1)?"se":"liulei");
        else if (nr[ll+2]>=rr)
            puts(((rr-ll+1-(nr[ll+1]-ll)-(nr[ll]>ll+1))&1)?"se":"liulei");
        else if (nr[ll+1]==rr-1)
            puts("liulei");
        else assert(0);
    }
    exit (0);
}
}
	

别看我这坨带便了好不好)

标签:noi,ac775,int,题解,ll,mid,len,rr,单调
From: https://www.cnblogs.com/white-ice/p/18490475

相关文章

  • CSP2024 前集训:多校A层冲刺NOIP2024模拟赛10
    前言不想说啥了最简单的一题是紫,去死吧只改了T1、T2,T2原题翻译和赛时题面描述都很唐,赛后断断续续加了好多hack。T1岛屿设\(f_{a,b}\)表示\(a\)条两端同色链,\(b\)条两端异色链时连通块数量的期望。红红蓝蓝相连得到红蓝\(\tof_{a-1,b+1}\)。红红红蓝相连得到红红......
  • NOIP2024集训Day57 哈希
    NOIP2024集训Day57哈希A.[CF213E]TwoPermutations考虑到都是排列,值域连续,于是\(a\)都加\(x\)之后相当于在值域上平移了一段,也是连续的。由于要进行比较,个很容易想到哈希。\(a\)的哈希值很好维护,每次平移一位加上\(\sumbase^i\)即可。考虑如何快速取出\(b\)中在......
  • ZZJC新生训练赛第七场题解
    难度分类(同一难度下按字典序上升)入门:C简单:G,D中等:E,H,F,A困难:BC-解题思路数一下每个字母的数量看是不是偶数就可以得到答案。C-代码实现#include<bits/stdc++.h>intmain(){std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout......
  • [赛记] 多校A层冲刺NOIP2024模拟赛09 && 10
    排列最小生成树(pmst)50pts又是诈骗题,然后又不会。。。暴力很暴力,直接建个完全图跑Kruskal即可;正解考虑如果我们连接编号相邻的点,那么每个边的边权都小于$n$真能考虑到吗?;所以我们最终的最小生成树中的边边权都小于$n$;那么对于$|p_i-p_j|\times|i-j|<n$......
  • NOI2024 D1T1 - 集合 题解
    观察我们称\(x\)在一段序列中的“位置集合”为\(x\)出现的下标的集合。注意到,两段序列能够匹配,当且仅当两段序列的\(1\simm\)中的数的位置集合构成的多重集相等。快速比较集合,考虑哈希。哈希先实现一个从整数到整数的哈希\(f(x)\)。使用这个哈希的目的是为了提高随机......
  • 考场环境 NoiLinux 测试
    觉得还是有必要提前练一下用的是官网的NoiLinux.iso全程断网下载虽然不知道实机预安装系统时是不是断网的NoiLinux,但是保险一点还是选了断网省选的时候,Windows里只有画图和Dev-C++分辨率非常构式,需要手动调分辨率,咱们电脑是1920*1080(没找到适配这个电脑的分辨率),到时......
  • 题解 P11220 / MX241020D【【MX-S4-T4】「yyOI R2」youyou 的三进制数】
    好长的标题题目描述现在有\(0\simn\)共\(n+1\)个数。定义\((x)_{3}\)表示十进制数\(x\)的三进制形式。如果没有特别强调,那么这些数均为十进制形式。youyou想构造一个序列长度为\(p\)(\(p\ge1\))的非负整数序列\(a\)。使之满足:\(a_i\in[0,n]\)。不存在\(i......
  • P9890 [ICPC2018 Qingdao R] Tournament 题解
    P9890[ICPC2018QingdaoR]Tournament题目传送门更好的阅读体验一道找规律的思维题。前置知识\(lowbit\)\(lowbit\)是指获取一个二进制数中最右边的\(1\)所对应的数值。具体地,\(lowbit\)可以通过对一个数取反然后加\(1\),再与原数进行按位与的方式来实现。intlow......
  • ZZJC新生训练赛第六场题解
    先给出比赛链接:下面说一下难度分层:(同一难度下按字典序排序)Easy(简单):BHMedium(中等):DEHard(困难):AGAnti-AK(防AK):CFA扣分扣分扣分!扣分!二维前缀差分板子题题目要求对二维区间加某个数或者查询二维区间的和与一维前缀和类似地,我们定义$sa[i][j]$为区间(......
  • 多校A层冲刺NOIP2024模拟赛10
    因为有好多人没有好好打,所以我认为我垫底了。赛时rank2,T10pts,T2100pts,T30pts,T440pts,accoder上同分,rank9。T1因为没输出挂了5pts,T4爆搜挂了5pts,乐。update:T3没有启发式合并被卡成rank4了神:wang5是下一个zh0ukangyang岛屿唐氏的推柿子题。发现只有两种链,同色相连和......