牛客多校第二场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;
}
posted @ 2021-08-22 06:59  1427314831a  阅读(53)  评论(0编辑  收藏  举报