牛客多校第二场B(组合计数)
作者:互联网
2021牛客多校第二场B(组合计数) B-Cannon_2021牛客暑期多校训练营2 (nowcoder.com)
题意:
有一个\(2\times10^{100}\) 的棋盘,第一行摆了 a个炮,第二行摆了b个炮
求依次发生 k 个炮吃炮事件的方案数,对 \(10^9+9\)取模
同时分为两个子问题
子问题1,没有任何限制
子问题2,取完上面后只能接着往下面取
\(1\le a,b\le5\times10^6\)
思路:
当一行有n个炮时,从左往右去看会发生n-2种炮吃炮的情况,同理反过来从右往左也有n-2种,一共2(n-2)种
那么n个炮操作m次的方案数为\(2(n-2)\times2(n-2-1)\times\cdots\times2(n-2-(m-1))=2^m\frac{(n-2)!}{(n-2-m)!}\)
令n=a-2,m=b-2,那么该问题即转化成了对每个k求
子问题1:\(2^k\sum \left(\matrix{k\\i}\right)\frac{n!}{(n-i)!}\frac{m!}{(m-(k-i))!}\)
子问题2:\(2^k\sum\frac{n!}{(n-i)!}\frac{m!}{(m-(k-i))!}\)
看起来似乎2的式子比1简单,但实际上正好相反
对子问题1有:\(2^k\sum \left(\matrix{k\\i}\right)\frac{n!}{(n-i)!}\frac{m!}{(m-(k-i))!}\\=2^k\sum\frac{k!}{i!(k-i)!}\frac{n!}{(n-i)!}\frac{m!}{(m-(k-i))!}\\=2^k\sum k!\left(\matrix{n\\i}\right)\left(\matrix{m\\k-i}\right)\\=2^kk!\sum\left(\matrix{n\\i}\right)\left(\matrix{m\\k-i}\right)\\=2^kk!\left(\matrix{n+m\\k}\right)\)
预处理组合数即可对每个k O(1)求解
对子问题2有:\(2^k\sum\frac{n!}{(n-i)!}\frac{m!}{(m-(k-i))!}=2^k\sum\frac{n!m!}{(n+m-k)!}\frac{(n+m-k)!}{(n-i)!(m-(k-i))!}\\=2^k\sum\frac{n!m!}{(n+m-k)!}\left(\matrix{n+m-k\\n-i}\right)=2^k\frac{n!m!}{(n+m-k)!}\sum_{i=n-k}^{n}\left(\matrix{n+m-k\\i}\right)\)
令\(S(n,m)=\sum_{i=0}^{m}\left(\matrix{n\\i}\right)\)
\(S(n,m+1)=S(n,m)+\left(\matrix{n\\m+1}\right)\)
\(S(n,m-1)=S(n,m)-\left(\matrix{n\\m}\right)\)
\(S(n+1,m)=\sum_{i=0}^{m}\left(\matrix{n+1\\i}\right)=\sum_{i=0}^{m}\left(\matrix{n\\i}\right)+\left(\matrix{n\\i-1}\right)\\=S(n,m)+S(n,m-1)=2S(n,m)-\left(\matrix{n\\m}\right)\)
\(S(n,m)=\frac{1}{2}S(n+1,m)+\frac{1}{2}\left(\matrix{n\\m}\right)\)
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+9;
const int maxn=1e7;
int fac[maxn+20],inv[maxn+20],gs[maxn+20];
int ksm(int a,int b)
{
int res=1;
while(b)
{
if(b&1)res=1ll*res*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return res;
}
int inv2=ksm(2,mod-2);
int C(int n,int m)
{
if(m<0||n<0)return 0;
int res=fac[n];
res=1ll*res*inv[m]%mod;
res=1ll*res*inv[n-m]%mod;
return res;
}
int main()
{
fac[0]=1;inv[0]=1;inv[1]=1;gs[0]=1;
for(int i=2;i<=maxn;i++)
{
inv[i]=(mod-1ll*(mod/i)*inv[mod%i]%mod);
}
for(int i=1;i<=maxn;i++)
{
fac[i]=1ll*fac[i-1]*i%mod;
inv[i]=1ll*inv[i-1]*inv[i]%mod;
gs[i]=(gs[i-1]<<1)%mod;
}
int a,b,ans1=0,ans2=0;
cin>>a>>b;
int n=a-2,m=b-2;
int mc=1;
for(int k=0;k<=m+n;k++)
{
// cout<<fac[k]<<" "<<mc<<" "<<C(n+m,k)<<"\n";
ans1^=(1ll*mc*fac[k]%mod*C(n+m,k)%mod);
mc=(mc<<1)%mod;
}
if(n>m)swap(n,m);
mc=1;
int sum1=0,sum2=0;
for(int i=0;i<=n;i++)
{
sum1=(1ll*sum1+C(n+m,i))%mod;
}
sum2=(1ll*sum1-C(n+m,n)+mod)%mod;
for(int k=0;k<=n+m;k++)
{
int tmp=1ll*mc*fac[n]%mod*fac[m]%mod*inv[n+m-k]%mod;
mc=(mc<<1)%mod;
if(k>m)
{
// cout<<1ll*tmp*ksm(2,n+m-k)%mod<<"hhh\n";
ans2^=1ll*tmp*gs[n+m-k]%mod;
continue;
}
else if(k>=n)
{
// cout<<1ll*tmp*sum1%mod <<"\n";
ans2^=1ll*tmp*sum1%mod;
sum1=(1ll*sum1*inv2%mod+1ll*C(n+m-k-1,n)*inv2%mod)%mod;
}
else
{
// cout<<1ll*tmp*(sum1-sum2+mod)%mod<<"\n";
ans2^=1ll*tmp*(sum1-sum2+mod)%mod;
sum1=(1ll*sum1*inv2%mod+1ll*C(n+m-k-1,n)*inv2%mod)%mod;
sum2=(1ll*sum2*inv2%mod-1ll*C(n+m-k-1,n-k-1)*inv2%mod+mod)%mod;
}
}
cout<<ans1<<" "<<ans2<<"\n";
return 0;
}
标签:第二场,right,frac,matrix,int,sum,多校,牛客,left 来源: https://www.cnblogs.com/1427314831a/p/15171206.html