• luogu P3726 [AH2017/HNOI2017]抛硬币


    传送门

    我是真的弱,看题解都写了半天,,,

    这题答案应该是(sum_{i=1}^{a}inom{a}{i}sum_{j=0}^{min(b,i-1)}inom{b}{j})

    上面那个式子无法化简qwq

    把A和b的抛硬币情况连在一起,记成一个01串,那么如果某个串代表B获胜,那么这个串的反串就能代表A获胜

    如果(a=b),那么答案还要减去平局情况,即$$frac{2^{a+b}-inom{a+b}{a}}{2}$$

    如果(a>b),那么有种特殊情况是代表A获胜的某个串反串还是代表A获胜,这种情况假设B硬币朝上个数为(i),A的朝上个数比B多(i),那么有(b-i<a-i-j),情况数量有$$sum_{i=0}{b}sum_{j=1}{a-b-1}inom{a}{i+j}inom{b}{i}$$个,也就是$$sum_{i=0}{b}sum_{j=1}{a-b-1}inom{a}{i+j}inom{b}{b-i}$$然后有个什么范德蒙德卷积,就是(sum_{i+j=k}inom{a}{i}inom{b}{j}=inom{a+b}{k}),所以上式化简为$$sum_{i=1}^{a-b-1}inom{a+b}{b+i}$$
    答案即$$frac{2{a+b}+sum_{i=1}{a-b-1}inom{a+b}{b+i}}{2}$$

    然后因为模数不为质数,所以组合数要用(exlucas)

    注意在实现的时候要优化时间复杂度,例如预处理模2和模5的阶乘等

    #include<bits/stdc++.h>
    #define LL long long
    #define il inline
    #define re register
    #define db double
    
    using namespace std;
    il LL rd()
    {
      LL x=0,w=1;char ch=0;
      while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
      while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
      return x*w;
    }
    LL a,b,k,K,k2,k5;
    LL fc[2][2000000];
    int pm[30][2],tt;
    il LL fpow(LL a,LL b,LL mod)
    {
      LL an=1;
      while(b){if(b&1) an=an*a%mod;a=a*a%mod,b>>=1;}
      return an;
    }
    il void exgcd(LL a,LL b,LL &x,LL &y)
    {
      if(!b) {x=1,y=0;return;} 
      exgcd(b,a%b,y,x);
      y-=a/b*x;
    }
    il LL ginv(LL a,LL b)
    {
      LL x,y;
      exgcd(a,b,x,y);
      return (x%b+b)%b;
    }
    il LL fac(LL n,LL p1,LL pk)
    {
      if(n<=1) return 1;
      LL an=fpow(fc[p1&1][pk],n/pk,pk)*fc[p1&1][n%pk]%pk;
      return an*fac(n/p1,p1,pk)%pk;
    }
    il LL C(LL n,LL m,LL p1,LL pk,bool d2)
    {
      LL kk=0;
      for(LL i=n;i;i/=p1) kk+=i/p1;
      for(LL i=m;i;i/=p1) kk-=i/p1;
      for(LL i=n-m;i;i/=p1) kk-=i/p1;
      if(kk-1>=k) return 0; //kk-1>=k,所以a*p^kk=0(mod p^k)
      if(d2)
        {
          if(p1&1) kk=fpow(p1,kk,pk)*ginv(2,pk)%pk;
          else kk=fpow(p1,kk-1,pk);
        }
      else kk=fpow(p1,kk,pk);
      return fac(n,p1,pk)*ginv(fac(m,p1,pk),pk)%pk*ginv(fac(n-m,p1,pk),pk)%pk*kk%pk;
    }
    il LL exlcs(LL n,LL m,bool d2)
    {
      return (C(n,m,2,k2,d2)*k5%K*ginv(k5,k2)%K+C(n,m,5,k5,d2)*k2%K*ginv(k2,k5)%K)%K;
    }
    il void init(int a,int b)
    {
      int px=a&1;
      fc[px][0]=1;
      for(int i=1;i<=b;++i)
        {
          fc[px][i]=fc[px][i-1];
          if(i%a) fc[px][i]=fc[px][i]*i%b;
        }
    }   //预处理fac函数中的计算部分
    il void print(int x,int kk)
    {
      kk/=10;
      while(kk) putchar(x/kk%10+'0'),kk/=10;
      putchar('
    ');
    }
    
    int main()
    {
      init(2,512),init(5,1953125);
      while(scanf("%lld%lld%lld",&a,&b,&k)!=-1)
        {
          K=k2=k5=1;
          int kb=k;while(kb--) K*=10,k2*=2,k5*=5;
          if(a==b) print((fpow(2,a+b-1,K)-exlcs(a+b,a,1)+K)%K,K);
          else
            {
              LL an=fpow(2,a+b-1,K);
              for(LL i=b+1;i<=(a+b)/2;++i)
                an=(an+exlcs(a+b,i,0)%K)%K; //根据C(a,b)=C(a,a-b)省去一半计算
              if(!((a+b)&1)) an=(an-exlcs(a+b,(a+b)/2,1)+K)%K;  
              print(an,K);
            }
        }
      return 0;
    }
    
  • 相关阅读:
    Javascript之DOM的三大节点及部分用法
    Javascript之全局变量和局部变量部分讲解
    《TCP/IP详解 卷1:协议》系列分享专栏
    说一说MySQL的锁机制
    《TCP/IP详解 卷1:协议》第3章 IP:网际协议
    PHP连接MySql闪断自动重连的方法
    关于MySQL的锁机制详解
    React 源码中的依赖注入方法
    《Mysql高级知识》系列分享专栏
    《AngularJS学习整理》系列分享专栏
  • 原文地址:https://www.cnblogs.com/smyjr/p/10108081.html
Copyright © 2020-2023  润新知