HDU:Turn the pokers

HDU:Turn the pokers

题目链接:https://cn.vjudge.net/contest/163787#overview

题目大意:现有$m$张正面朝下的扑克牌,接下来有$n$次操作,每次可以将$X_i$张扑克翻转,问最终扑克的朝向方案有多少种.

贪心

易得,如果结果有$k$张扑克为正面朝上,那么答案将所有$k$张正面朝上的方案,从而只需计算最终可能有哪些$k$存在.

根据翻转的特点(翻转后所有的$k$值奇偶性相同)有,每次操作后可能存在的$k$值为公差为$2$的等差数列,

故每次操作只需维护最小$k$值$l$和最大$k$值$r$即可.

不难得到:

  • $l_{i+1}=min{|X_i-a|:l_i leqslant a leqslant r_i}$
  • $r_{i+1}=m-min{|X_i-(m-a)|:l_i leqslant a leqslant r_i}$

最后求得$ans=sum_{k=l}^{k=r}(_k^m)$.

/*坑点:p=1e9+9*/

代码如下:

 1 #include <cstdio>
 2 #define N 100000
 3 using namespace std;
 4 typedef long long ll;
 5 const ll p=1e9+9;
 6 ll fac[N+5],inv_fac[N+5],n,m;
 7 ll powmod(ll a,ll n){
 8     ll r=1;
 9     while(n){
10         if(n&1)r=(r*a)%p;
11         a=(a*a)%p;
12         n>>=1;
13     }
14     return r;
15 }
16 ll C(ll m,ll n){
17     return fac[n]*inv_fac[m]%p*inv_fac[n-m]%p;
18 }
19 void init(){
20     fac[0]=1;
21     for(int i=1;i<=N;++i)
22         fac[i]=(fac[i-1]*i)%p;
23     inv_fac[N]=powmod(fac[N],p-2);
24     for(int i=N-1;i>=0;--i)
25         inv_fac[i]=(inv_fac[i+1]*(i+1))%p;
26 }
27 ll fmin(ll l,ll r,ll x){
28     if(l<=x&&x<=r)return (x-l)%2;
29     else if(x<l)return l-x;
30     else return x-r;
31 }
32 ll fmax(ll l,ll r,ll x){
33     return m-fmin(m-r,m-l,x);
34 }
35 int main(void){
36     init();
37     while(~scanf("%lld%lld",&n,&m)){
38         ll l=0,r=0,x,ans=0;
39         while(n--){
40             scanf("%lld",&x);
41             ll tl=fmin(l,r,x);
42             ll tr=fmax(l,r,x);
43             l=tl;r=tr;
44         }
45         for(ll i=l;i<=r;i+=2)
46             ans=(ans+C(i,m))%p;
47         printf("%lld
",ans);
48     }
49 }
原文地址:https://www.cnblogs.com/barrier/p/6850727.html