题解 | 信息学奥赛一本通 取石子游戏

取石子游戏

https://ac.nowcoder.com/acm/contest/983/H

思路

首先,函数什么的不怎么管用.(亏我想了好久)
这题做法十分神奇.
表示在区间[l,r]的石子左边添加一堆L[i][j]的石子会导致先手必败,如果没有该种策略值为0.与此同理.
易证决策不可能吧同时存在多个.
预处理边界.因为相同的两堆会导致这样的情况:先手在一堆取多少,后手就在后一堆取多少,先手明显必败.
然后中间的决策可以推过去.设


  1. 这样是一个必败态,不管在左边放怎样的石子堆先手都可以取完这一堆引来必败态,所以.

  2. .先手在某一边取多少(未取完),后手就在另一边取多少如果先手把一边取完了,后手面临的情况可以看做的石子在左边或右边放一堆石子,且不为.前面说过,必败的放石子方案是唯一的,因此这个局面是必胜的.

  3. .然后执行以下几个策略.
    若先手取左边,并且,我们维持状态即可(也就是先手取多少,就在另一堆取多少).
    若先手取左边,并且,我们把右边那堆取光,然后先手就面临必败态了.
    若先手取左边,并且(未取光),我们把右边那堆也取到相同数目的石子,这样局面就相当于且先后手各取完一轮时,先手必输.
    若先手取左边且取光,右边很明显不会为,是必胜态.
    若先手取右边,并且未取光,我们把直接把左边取成与右边相同即可,这样就相当于且先后手各取完一轮的状态.
    若先手取右边且取光,我们把左边取到,然后就是必败态了.

  4. 分析同上..

  5. .分析也是类似的.如果还是,维持状态.
    如果,就变成状态2.
    否则会变成状态3或4,对应地变成先手取剩的石子+1/-1即可.

    代码

#include<bits/stdc++.h>
using namespace std;
#define i64 long long
#define fp( i, b, e ) for ( int i(b), I(e); i <= I; ++i )
#define fd( i, b, e ) for ( int i(b), I(e); i >= I; --i )
#define go( i, b ) for ( int i(b), v(to[i]); i; v = to[i = nxt[i]] )
template<typename T> inline void cmax( T &x, T y ){ x < y ? x = y : x; }
template<typename T> inline void cmin( T &x, T y ){ y < x ? x = y : x; }
#define getchar() ( p1 == p2 && ( p1 = bf, p2 = bf + fread( bf, 1, 1 << 21, stdin ), p1 == p2 ) ? EOF : *p1++ )
char bf[1 << 21], *p1(bf), *p2(bf);
template<typename T>
inline void read( T &x ){ char t(getchar()), flg(0); x = 0;
    for ( ; !isdigit(t); t = getchar() ) flg = t == '-';
    for ( ; isdigit(t); t = getchar() ) x = x * 10 + ( t & 15 );
    flg ? x = -x : x;
}

clock_t t_bg, t_ed;
const int MAXN = 1e3 + 5;
int T, N, a[MAXN];
int L[MAXN][MAXN], R[MAXN][MAXN];

signed main(){
    t_bg = clock();
    read(T);
    while( T-- ){
        read(N);
        fp( i, 1, N ) read(a[i]), L[i][i] = R[i][i] = a[i];
        fp( len, 2, N ) fp( i, 1, N - len + 1 ){
            int j = i + len - 1, l, r, x;
            l = L[i][j - 1], r = R[i][j - 1], x = a[j];
            if ( x == r ) L[i][j] = 0;
            else if ( ( x < l && x < r ) || ( x > l && x > r ) ) L[i][j] = x;
            else if ( l <= x && x < r ) L[i][j] = x + 1;
            else L[i][j] = x - 1;
            l = L[i + 1][j], r = R[i + 1][j], x = a[i];
            if ( l == x ) R[i][j] = 0;
            else if ( ( x < l && x < r ) || ( x > l && x > r ) ) R[i][j] = x;
            else if ( r <= x && x < l ) R[i][j] = x + 1;
            else R[i][j] = x - 1;
        } printf( a[1] == L[2][N] ? "0\n" : "1\n" );
    }
    t_ed = clock();
    fprintf( stderr, "\n========info========\ntime : %.3f\n====================\n", (double)( t_ed - t_bg ) / CLOCKS_PER_SEC );
    return 0;
}
全部评论

相关推荐

不愿透露姓名的神秘牛友
05-29 22:21
Offer1:小马智行,深圳,测试开发工程师,17.0k*16.0,Offer2:追觅科技,深圳,嵌入式工程师,18.0k*15.0,
嵌软狗都不学:各位base深圳的同事,作为也是并肩作战的一员,今天想站在管理视角,和大家开诚布公地聊一聊:从近几个月的上下班数据对比看来,我们发现一个明显的差异:深圳同事的在岗时间普遍比苏州同事短。很多深圳同事早上9点之后才到公司,晚上不到 20 点就下班了;而总部那边,20点半甚至 22 点后还有不少同事在办公室忙碌,特别是研发团队,加班更是常态。相信去过苏州的同事,对这种场景都不陌生。我很好奇,这是因为苏州工作任务太重还是咱们深圳同事效率真的高到能在更短时间内完成工作?MOVA在深圳成立分公司是为了吸引更优秀的人才贡献更多更高质的价值,公司管理层给我反馈的是深圳招到的多是行业的专家大拿,大部分都是薪资比苏州高的,而且我们办公的租金等也远高于苏州的..MOVA虽脱胎于强壮的集团母体不久,各业务板块尚未实现全面盈利,虽说公司管理层目光长远,不纠结当下的人才投入,但行业内的普遍标准是,员工创造的价值要达到公司雇佣成本的 15 倍以上。大家不妨自我审视一下,自己是否达到了这个标准?如果是抱着划水、按时打卡走人拿毛爷爷的心态那不适合来MOVA,那样过下去不但自己过得尴尬也会影响MOVA这个大船的攻城略地的速度.我并非鼓励大家盲目加班,而是倡导高效工作,拒绝无效忙碌,不要让项目进度因低效受影响,也别把精力浪费在和苏州同事拼打卡时长上,提倡更高的人效比;考虑到两地地域和交通差异,相信大家会找最适合自己发挥的工作方式(比如按时下班后1小时到家晚饭后继续未竟工作等..)大家在遵守公司规章的情况下尽情地体现自己的能力价值,为MOV!和深圳公司争光我们在这边才能更安心更有信心的工作下去;请客BU长、名部门长、项目管理和各业务单元负责人,全面梳理团队情况,及时评估成员工作负荷与成果质量,坚决清退划水害虫痕疫,践行公司价值观,相互监督,防止管理漏洞及渎职。感谢人家的理解,也请人家多担待我的直言不讳……
点赞 评论 收藏
分享
05-07 17:58
门头沟学院 Java
wuwuwuoow:1.简历字体有些怪怪的,用啥写的? 2.Redis 一主二从为什么能解决双写一致性? 3.乐观锁指的是 SQL 层面的库存判断?比如 stock > 0。个人认为这种不算乐观锁,更像是乐观锁的思想,写 SQL 避免不了悲观锁的 4.奖项证书如果不是 ACM,说实话没什么必要写 5.逻辑过期时间为什么能解决缓存击穿问题?逻辑过期指的是什么 其实也没什么多大要改的。海投吧
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务