【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; }
相关文章
相关标签/搜索