题目来源:NOI2018模拟测试赛(二十六)
题解:
设a<b;
可以先考虑a=1的特殊情况,注意到后手的最优策略是跟着另外一个人取,取到最后剩余不到$a+b$时再看奇偶性;
那么很容易想到把所有石子按$mod(a+b)$的余数分类:
1.余数<a:剩下的部分没用;
2.a≤余数<b:只要有则a必胜;
3.b≤余数<2a:要考虑奇偶性;
4.余数≥2a:只要有两个或以上则a必胜,有一个时情况3的为偶数则先手必胜,为奇数则a必胜,没有时情况3为偶数则后手必胜,否则先手必胜;
随便手推一下就行了。
ps:场上会a=b和a=1的都写了正解,就我一个zz不会还写挂了部分分……
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<cmath>
6 #include<queue>
7 #define inf 2147483647
8 #define eps 1e-9
9 #define mod 1000000007
10 using namespace std;
11 typedef long long ll;
12 typedef double db;
13 int n,a,b,s1,s2,s3,s4,t1,t2,t3,t4,tot=0,x[100001],s[100001];
14 bool sw=false;
15 int fastpow(int x,int y){
16 int ret=1;
17 for(;y;y>>=1,x=(ll)x*x%mod){
18 if(y&1)ret=(ll)ret*x%mod;
19 }
20 return ret;
21 }
22 int main(){
23 scanf("%d%d%d",&n,&a,&b);
24 if(a>b){
25 sw=true;
26 swap(a,b);
27 }
28 for(int i=1;i<=n;i++){
29 scanf("%d",&x[i]);
30 x[i]%=(a+b);
31 if(x[i]<a)s1++;
32 else if(x[i]<b)s2++;
33 else if(x[i]<a*2)s3++;
34 else s4++;
35 }
36 if(s3){
37 t3=t4=fastpow(2,s1+s3-1);
38 }else t4=fastpow(2,s1);
39 t3=(t3+(ll)t4*s4%mod)%mod;
40 t1=((fastpow(2,n)-t3-t4)%mod+mod)%mod;
41 if(sw)swap(t1,t2);
42 printf("%d %d %d %d",t1,t2,t3,t4);
43 return 0;
44 }