题目: 传送门
思路: 根据最后一轮的输赢推出最后一轮的先后手(看先手必赢还是后手必赢或者看先手必输还是后手必输),再推出上一轮的输赢(输赢-->先后手);
那么如何判断每一轮是先手可以必赢还是后手可以必赢呢?
若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 ",w[i],l[i]); 88 } 89 printf("%d %d ",check(n,1),check(n,0)); 90 return 0; 91 }