[AH2017HNOI2017]抛硬币

    科技2022-08-16  104

    一、题目

    点此看题

    二、解法

    前置芝士:范德蒙德卷积: C ( n + m , k ) = ∑ i = 0 k C ( n , i ) C ( m , k − i ) C(n+m,k)=\sum_{i=0}^kC(n,i)C(m,k-i) C(n+m,k)=i=0kC(n,i)C(m,ki)这道题的暴力算式是很好写的,但是优化不动,因为用不到 a − b ≤ 10000 a-b\leq10000 ab10000,从最简单的情况考虑:

    部分分:a=b

    此时 a , b a,b a,b公平竞争,对于 a a a赢着的情况,一定严格对应一种 a a a输着的情况(把他们的输赢情况反转),那么我们考虑算出他们平局的情况,用所有情况减去除 2 2 2即是答案,平局算式如下: ∑ i = 0 a C ( a , i ) 2 = ∑ i = 0 a C ( a , i ) C ( a , a − i ) = C ( 2 a , a ) \sum_{i=0}^aC(a,i)^2=\sum_{i=0}^aC(a,i)C(a,a-i)=C(2a,a) i=0aC(a,i)2=i=0aC(a,i)C(a,ai)=C(2a,a)所以答案是: 2 a + b − C ( 2 a , a ) 2 \frac{2^{a+b}-C(2a,a)}{2} 22a+bC(2a,a)a>b

    有点难,按照部分分的对应法则我们发现有些 a a a赢的情况反转时候还是赢的,我们称这种现象叫不对称,记对称的方案数是 S 1 S_1 S1,不对称的方案数是 S 2 S_2 S2,则有这样的关系: S 1 + S 2 = 2 a + b , a n s = S 1 2 + S 2 S_1+S_2=2^{a+b},ans=\frac{S_1}{2}+S_2 S1+S2=2a+b,ans=2S1+S2我们只需要求出其中一个就行了,求对称的只能暴力,所以我们去算 S 2 S_2 S2,我们考虑此时满足什么样的关系,用形式上的表达,记 ∣ a ∣ |a| a a a a 1 1 1个数, ∣ b ∣ |b| b b b b 1 1 1个数: ∣ a ∣ > ∣ b ∣ , a − ∣ a ∣ > b − ∣ b ∣ |a|>|b|,a-|a|>b-|b| a>b,aa>bb也就是 a − b > ∣ a ∣ − ∣ b ∣ a-b>|a|-|b| ab>ab,这时候出现了 a − b a-b ab就很舒服了,盯准它,枚举 ∣ b ∣ |b| b ∣ a ∣ − ∣ b ∣ |a|-|b| ab S 2 = ∑ i = 0 b C ( b , i ) ∑ j = 1 a − b − 1 C ( a , i + j ) S_2=\sum_{i=0}^bC(b,i)\sum_{j=1}^{a-b-1}C(a,i+j) S2=i=0bC(b,i)j=1ab1C(a,i+j) ∑ j = 1 a − b − 1 ∑ i = 0 b C ( b , b − i ) C ( a , i + j ) \sum_{j=1}^{a-b-1}\sum_{i=0}^bC(b,b-i)C(a,i+j) j=1ab1i=0bC(b,bi)C(a,i+j) ∑ j = 1 a − b − 1 C ( a + b , b + j ) \sum_{j=1}^{a-b-1}C(a+b,b+j) j=1ab1C(a+b,b+j)然后用算出上式这道题就结束了,模数其实是 1 e 9 1e9 1e9,非质数,考虑扩展卢卡斯, 1 0 9 = 2 9 5 9 10^9=2^95^9 109=2959,对两个质数次幂做卢卡斯然后 c r t \tt crt crt合并就行了,需要预处理对于质因子 2 2 2 5 5 5的阶乘,算卢卡斯就可以 O ( log ⁡ 2 ) O(\log^2) O(log2)了(需要快速幂)

    还有问题,最后的除 2 2 2怎么解决, 2 2 2的次幂可以直接搞指数,对于我们算的组合数由于是杨辉三角上的 1 1 1行,具有其对称性,只用算一边就可以了,而如果 a + b a+b a+b是偶数 C ( a + b , ( a + b ) / 2 ) C(a+b,(a+b)/2) C(a+b,(a+b)/2)没有配对的,把他化到上一行变成 C ( a + b − 1 , ( a + b ) / 2 ) C(a+b-1,(a+b)/2) C(a+b1,(a+b)/2)就行了。还有一种方法就是把模数变成 2 e 9 2e9 2e9最后就可以直接除 2 2 2了。

    #include <cstdio> const int p = 1e9; #define int long long int read() { int num=0,flag=1;char c; while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1; while(c>='0'&&c<='9')num=(num<<3)+(num<<1)+(c^48),c=getchar(); return num*flag; } int n,m,a,b,k,y[20],mod[2]={512,1953125},bs[2]={2,5},fac[2][2000000]; void exgcd(int a,int b,int &x,int &y) { if(!b){x=1;y=0;return ;} exgcd(b,a%b,y,x);y-=x*(a/b); } int inv(int v,int p) { int x,y;exgcd(v,p,x,y); return (x%p+p)%p; } int qkpow(int a,int b,int p) { int r=1; while(b>0) { if(b&1) r=r*a%p; a=a*a%p; b>>=1; } return r; } int fuck(int n,int t) { if(!n) return 1; return qkpow(fac[t][mod[t]-1],n/mod[t],mod[t]) *fac[t][n%mod[t]]%mod[t]*fuck(n/bs[t],t)%mod[t]; } int L(int n,int m,int t) { int ind=0; for(int i=n;i;i/=bs[t]) ind+=i/bs[t]; for(int i=m;i;i/=bs[t]) ind-=i/bs[t]; for(int i=n-m;i;i/=bs[t]) ind-=i/bs[t]; if(ind>=9) return 0; int x=fuck(n,t),y=fuck(m,t),z=fuck(n-m,t); return x*inv(y,mod[t])%mod[t]*inv(z,mod[t])%mod[t]*qkpow(bs[t],ind,mod[t])%mod[t]; } void pr(int x) { for(int i=1;i<=k;i++,x/=10) y[i]=x%10; for(int i=k;i>=1;i--) printf("%lld",y[i]); puts(""); } signed main() { fac[0][0]=fac[1][0]=1; for(int i=1;i<mod[0];i++) fac[0][i]=(i%2)?i*fac[0][i-1]%mod[0]:fac[0][i-1]; for(int i=1;i<mod[1];i++) fac[1][i]=(i%5)?i*fac[1][i-1]%mod[1]:fac[1][i-1]; while(~scanf("%lld %lld %lld",&a,&b,&k)) { int r2=0,r5=0; if(a==b)//求C(2a,a) { r2=L(2*a-1,a,0);r5=L(2*a-1,a,1); r2=r2*mod[1]%p*inv(mod[1],mod[0])%p; r2=(r2+r5*mod[0]%p*inv(mod[0],mod[1])%p)%p; pr((qkpow(2,a+b-1,p)-r2+p)%p); } else { if((a+b)%2)//对称,算一边 { for(int i=b+1;i<=(a+b)/2;i++) r2=(r2+L(a+b,i,0))%p; for(int i=b+1;i<=(a+b)/2;i++) r5=(r5+L(a+b,i,1))%p; r2=r2*mod[1]%p*inv(mod[1],mod[0])%p; r2=(r2+r5*mod[0]%p*inv(mod[0],mod[1])%p)%p; pr((qkpow(2,a+b-1,p)+r2)%p); } else//单独算C(a+b,(a+b)/2) { for(int i=b+1;i<(a+b)/2;i++) r2=(r2+L(a+b,i,0))%p;r2=(r2+L(a+b-1,(a+b)/2,0))%p; for(int i=b+1;i<(a+b)/2;i++) r5=(r5+L(a+b,i,1))%p;r5=(r5+L(a+b-1,(a+b)/2,1))%p; r2=r2*mod[1]%p*inv(mod[1],mod[0])%p; r2=(r2+r5*mod[0]%p*inv(mod[0],mod[1])%p)%p; pr((qkpow(2,a+b-1,p)+r2)%p); } } } }
    Processed: 0.010, SQL: 9