1. 程式人生 > >[2018雅禮集訓1-2]取石子 分類討論+組合數學

[2018雅禮集訓1-2]取石子 分類討論+組合數學

題面
首先所有石子先對a+b取模不影響結果。先設a<b
然後每堆石子數有以下幾種情況。
1. [0,a) 跟沒有沒區別。
2. [a,b) 只有Alice能取,所以存在這樣的Alice必勝。
3. [b,2a) 兩個人都只能取一次,跟其奇偶性有關。
4. [2a,a+b) Alice一次就能把它取成情況2,然後Bob就gg了,所以存在兩個及以上Alice必勝,存在一個的話Bob還可以挽救一下,把它搞成情況1。
先把這四種情況個數統計出來。具體必勝情況如下:
Alice勝:
1. cnt2>0
2. cnt42
3. cnt4=1cnt3為奇。
Bob勝:不存在
先手勝:在c

nt2=0的情況下,
1. cnt4=1cnt3為偶
2. cnt4=0cnt3為奇
後手勝:在cnt2=0的情況下,
cnt4=0cnt3為偶

組合計數一下就好,根據組合數性質,n(n0)個數裡取奇數個的方案等於取偶數個的方案=2n1
所以要特判cnt3=0的時候!!!這場rank1因為沒判錯失AK!!!
程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int
maxn=100010; const int mod=1000000007; int n,x[maxn],a,b,cnt[4]; ll ans[4],mi[maxn]; int main() { scanf("%d%d%d",&n,&a,&b); mi[0]=1; for(int i=1;i<=n;i++) mi[i]=(mi[i-1]<<1)%mod; bool lab=(a>b); if(lab) swap(a,b); for(int i=1;i<=n;i++) scanf("%d
"
,&x[i]); for(int i=1;i<=n;i++) { x[i]%=(a+b); if(a<=x[i]&&x[i]<b) cnt[0]++; else if(b<=x[i]&&x[i]<2*a) cnt[1]++; else if(2*a<=x[i]) cnt[2]++; else cnt[3]++; } ans[0]=(mi[n]-mi[n-cnt[0]]+mi[cnt[1]+cnt[3]]*(mi[cnt[2]]-cnt[2]-1)%mod+mod)%mod; ans[2]=mi[cnt[3]+max(cnt[1]-1,0)]*cnt[2]%mod; if(cnt[1]) (ans[0]+=mi[cnt[3]+cnt[1]-1]*cnt[2]%mod)%=mod,(ans[2]+=mi[cnt[3]+cnt[1]-1])%=mod; ans[3]=mi[cnt[3]+max(cnt[1]-1,0)]%mod; swap(ans[0],ans[lab]); for(int i=0;i<=3;i++) printf("%lld ",ans[i]); return 0; }