【HDU4869】Turn the pokers-思惟

測試地址:Turn the pokers
題目大意: m m 張牌,一開始正面都朝下,有 n n 次操做,每次操做給出一個 X i X_i ,表示要從這些牌中選出 X i X_i 張翻面,求全部操做完成後能獲得多少種不一樣的正/反面序列。
作法: 本題須要用到思惟。
由於將牌作任何置換都是合法的,所以只要咱們能構造出最後有 k k 張正面的狀況,就會對答案有 C m k C_m^k 的貢獻,所以問題就變成求哪些 k k 能夠獲得。
這裏有一個結論:若是 k k 的最小值是 L L ,最大值是 R R ,那麼在區間 [ L , R ] [L,R] 中全部與 L L R R 關於 2 2 同餘的數都是合法的 k k 。這個東西若是一會兒沒法理解,可使用數學概括的思想。假設某一次操做前知足這個性質,咱們只要證實通過一次操做後仍是知足這個性質便可。具體的證實各類分類討論比較麻煩,但感性理解仍是能夠的。所以咱們只要求 L L R R 便可。
咱們假設已經求出第 i i 次操做前的 L , R L,R ,那麼:
若是 X i L X_i\le L ,那麼 n e w L = L x newL=L-x
不然若是 X i R X_i\ge R ,那麼 n e w L = x R newL=x-R
不然,若是 X i X_i L L 關於 2 2 同餘, n e w L = 0 newL=0 ,不然 n e w L = 1 newL=1
這樣的分類討論應該仍是不難理解的,就是能把正面翻過去就把正面翻過去,這樣正面的數量就最小。
n e w R newR 的討論類似,只不過是能翻反面翻反面。這樣咱們就解決了這一題。
如下是本人代碼:php

#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1000000009; int n,m; ll fac[100010],inv[100010],invfac[100010]; ll C(ll n,ll m) { return fac[n]*invfac[m]%mod*invfac[n-m]%mod; } int main() { while(scanf("%d%d",&n,&m)!=EOF) { fac[0]=fac[1]=inv[1]=invfac[0]=invfac[1]=1; for(ll i=2;i<=m;i++) { fac[i]=fac[i-1]*i%mod; inv[i]=(mod-mod/i)*inv[mod%i]%mod; invfac[i]=invfac[i-1]*inv[i]%mod; } int L=0,R=0; for(int i=1;i<=n;i++) { int x; scanf("%d",&x); int nxtL,nxtR; if (x<=L) nxtL=L-x; else if (x>=R) nxtL=x-R; else nxtL=(x-L)%2; if (x<=m-R) nxtR=R+x; else if (x>=m-L) nxtR=2*m-L-x; else nxtR=m-((x-m+R)%2); L=nxtL,R=nxtR; } ll ans=0; for(int i=L;i<=R;i+=2) ans=(ans+C(m,i))%mod; printf("%lld\n",ans); } return 0; } #include <bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1000000009; int n,m; ll fac[100010],inv[100010],invfac[100010]; ll C(ll n,ll m) { return fac[n]*invfac[m]%mod*invfac[n-m]%mod; } int main() { while(scanf("%d%d",&n,&m)!=EOF) { fac[0]=fac[1]=inv[1]=invfac[0]=invfac[1]=1; for(ll i=2;i<=m;i++) { fac[i]=fac[i-1]*i%mod; inv[i]=(mod-mod/i)*inv[mod%i]%mod; invfac[i]=invfac[i-1]*inv[i]%mod; } int L=0,R=0; for(int i=1;i<=n;i++) { int x; scanf("%d",&x); int nxtL,nxtR; if (x<=L) nxtL=L-x; else if (x>=R) nxtL=x-R; else nxtL=(x-L)%2; if (x<=m-R) nxtR=R+x; else if (x>=m-L) nxtR=2*m-L-x; else nxtR=m-((x-m+R)%2); L=nxtL,R=nxtR; } ll ans=0; for(int i=L;i<=R;i+=2) ans=(ans+C(m,i))%mod; printf("%lld\n",ans); } return 0; }
相關文章
相關標籤/搜索