Codeforces Round #652 (Div. 2) F. BareLee(博弈论)

时间:2020-07-09
本文章向大家介绍Codeforces Round #652 (Div. 2) F. BareLee(博弈论),主要包括Codeforces Round #652 (Div. 2) F. BareLee(博弈论)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题目: 传送门 

思路: 根据最后一轮的输赢推出最后一轮的先后手(看先手必赢还是后手必赢或者看先手必输还是后手必输),再推出上一轮的输赢(输赢-->先后手);

    那么如何判断每一轮是先手可以必赢还是后手可以必赢呢?

    若e为奇数, s为偶数,先手必赢,否则后手必赢(若是偶数,先手一直加一即可,后手只能把奇数变成偶数);

    若e为偶数,s>e/2 (这样就只能执行+1操作) , s为奇数,先手必赢(先手+1操作后恒为偶),否则后手必赢 (s为奇数);

           e/4<s<=e/2 , 先手必赢 (直接乘以2,变成上一种情况的必赢态) ;

           s<=e/4 , 若[s , e/4] 先手可以必赢,那么[s,e] 先手可以必赢(  下一次先手操作的数字一定是 属于区间(e/4,e/2]  ),否则后手必赢 ;

    判断先手必输:

    若 s>e/2 (e>0) , 则先手可以必输。

    否则 ,若 [s,e/2] 先手可以必赢,那么[s,e] 先手可以必输,若不能必赢,则后手可以必输。

接下来就是代码实现了(里面有较为详细的注释)

 1 #include<bits/stdc++.h>
 2 /*
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<cstring>
 6 #include<vector>
 7 #include<cctype>
 8 #include<queue>
 9 #include<algorithm>
10 #include<map>
11 #include<set>
12 */
13 #pragma GCC optimize(2)
14 using namespace std;
15 typedef long long LL;
16 typedef unsigned long long uLL;
17 typedef pair<int,int> pii;
18 typedef pair<LL,LL> pLL;
19 typedef pair<double,double> pdd;
20 const int N=2e6+5;
21 const int M=1e4+5;
22 const int inf=0x3f3f3f3f;
23 const LL mod=1e9+7;
24 const double eps=1e-5;
25 const long double pi=acos(-1.0L);
26 #define ls (i<<1)
27 #define rs (i<<1|1)
28 #define fi first
29 #define se second
30 #define pb push_back
31 #define mk make_pair
32 #define mem(a,b) memset(a,b,sizeof(a))
33 LL read()
34 {
35     LL x=0,t=1;
36     char ch;
37     while(!isdigit(ch=getchar())) if(ch=='-') t=-1;
38     while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); }
39     return x*t;
40 }
41 int l[N],w[N];//l lose 表示先手能不能必输 1先手可以必输,w win 表示先手能不能必赢 1先手可以必赢
42 int check(int i,int flag)//flag表示这一轮的输赢 1赢 0输
43 {
44     if(i==1)
45     {
46         if(flag) return w[i];
47         else return l[i];
48     }
49     if(flag) return check(i-1,!w[i]);//这一轮赢
50     /*{
51         if(w[i]) return check(i-1,0); //如果这一轮是先手赢,上一轮一定是要输
52         else return check(i-1,1); //如果这一轮是后手赢,那么上一轮就要赢
53     }*/
54     else return check(i-1,!l[i]);
55 }
56 int dfs(LL s,LL e)//判断先手能否必赢
57 {
58     if(e&1)
59     {
60         if(s&1) return 0;
61         else return 1;
62     }
63     else
64     {
65         if(s>e/2)
66         {
67             if(s&1) return 1;
68             else return 0;
69         }
70         else if(s>e/4) return 1;
71         else return dfs(s,e/4);
72     }
73 }
74 int dfs2(LL s,LL e)//判断先手能否必输
75 {
76     if(s>e/2) return 1;
77     else return dfs(s,e/2)==1;//[s,e/2]先手必赢,才能有[s,e]先手必输。先手必赢那么接下来,后手操作完的a一定是>e/2,先手再乘以2就ok
78 }
79 int main()
80 {
81     int n=read();
82     for(int i=1;i<=n;i++)
83     {
84         LL s=read(),e=read();
85         w[i]=dfs(s,e);
86         l[i]=dfs2(s,e);
87         //printf("w = %d , l = %d\n",w[i],l[i]);
88     }
89     printf("%d %d\n",check(n,1),check(n,0));
90     return 0;
91 }
View Code

原文地址:https://www.cnblogs.com/DeepJay/p/13275492.html