欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

2020ICPC·小米 网络选拔赛热身赛-A.ABBA

程序员文章站 2022-07-02 11:38:21
地址:https://ac.nowcoder.com/acm/contest/8409/A思路:动态规划或组合数学思路一,动态规划:思路二,组合数学:...

2020ICPC·小米 网络选拔赛热身赛-A.ABBA

地址:https://ac.nowcoder.com/acm/contest/8409/A

思路:动态规划或组合数学

根据贪心思想,对于前n个A肯定用来组成AB,前m个B用来组成BA,因此对于y个A,x个B,

极端情况下x个A与B组成BA,那么剩余y-x个A必用来组成AB,因此 y-x<=n,同理 x-y<=m

思路一,动态规划:dp[y][x]=dp[y-1][x]+dp[y][x-1] , (y-x<=n,x-y<=m)

思路二,组合数学:https://ac.nowcoder.com/acm/discuss/blogs?tagId=139277

根据题意一共有n个AB和m个BA,即n+m个A和n+m个B的组合,

首先在2*(n+m)个空位里填上A,其余填B,一共有C(2*(n+m),n+m)种选法,然后去除不合理项。

什么情况下不合理呢,根据贪心思想,前n个A属于n,设当前A的数量为y,B的数量为x,y要保证小于等于x+n。同理,可以得到x要保证小于等于y+m。

2020ICPC·小米 网络选拔赛热身赛-A.ABBA

x轴代表B的数量,y轴代表A的数量,可行解范围如图,

题意即可转化为从(0,0)走到(n+m,n+m)不穿过y=x+n和x=y+m两条线的走法。

下面讲一下怎么求,

假设我们是在求从(0,0)到(n,m)不穿过对角线的走法,我们可以把对角线向下平移一格,得到线 l2,即到达线 l2 就一定穿过了对角线;

这样我们取(0,0)关于 线l2 的对称点(1,-1),如果从点(1,-1)走到(n,m)就一定经过线 l2,

可以发现从(1,-1)到(n,m)的路径首先与(0,0)穿过对角线到达线 l2 的路径关于线对称,然后从线 l2 到达(n,m)的路线相同,详情可以参考下图:

2020ICPC·小米 网络选拔赛热身赛-A.ABBA

即路径数为C(n+m,n)-C(n+m,m-1)。

由此方法可以推出E题结论为C(2*(n+m),n+m)-C(2*(n+m),n-1)-C(2*(n+m),m-1)。

Code 1:

#include<iostream>
using namespace std;
typedef long long LL;

const int MAX_S=2e3+5;
const LL Mod=1e9+7;
int n,m;
LL dp[MAX_S][MAX_S];

int main()
{
	ios::sync_with_stdio(false);
	while(cin>>n>>m){
		int s=n+m;
		dp[0][0]=1;
		for(int i=0;i<=s;++i)
		{
			dp[i][0]=dp[0][i]=0;
			if(i<=n)	dp[i][0]=1;
			if(i<=m)	dp[0][i]=1;
		}
		for(int i=1;i<=s;++i)
			for(int j=1;j<=s;++j)
				if(i-j<=n&&j-i<=m)	dp[i][j]=(dp[i][j-1]+dp[i-1][j])%Mod;
				else	dp[i][j]=0;
		cout<<dp[s][s]<<endl;
	}
	
	return 0;
}

Code 2:

#include<iostream>
using namespace std;
typedef long long LL;

const int MAX_S=4e3+5;
const LL Mod=1e9+7;
int n,m;
LL a[MAX_S];

LL Qpow(LL a,LL b){
	int ans=1;
	while(b){
		if(b&1)	ans=ans*a%Mod;
		a=a*a%Mod;
		b>>=1;
	}
	return ans;
}

LL C(LL n,LL m){
	if(m==-1)	return 0;
	return a[n]*Qpow(a[m]*a[n-m]%Mod,Mod-2)%Mod;
}
// ans=C(2(n+m),n+m)-C(2(n+m),n-1)-C(2(n+m),m-1)
int main()
{
	ios::sync_with_stdio(false);
	a[0]=1;
	for(int i=1;i<MAX_S;++i)
		a[i]=a[i-1]*i%Mod;
	while(cin>>n>>m){
		cout<<(C(2*(n+m),n+m)-C(2*(n+m),n-1)-C(2*(n+m),m-1)+2*Mod)%Mod<<endl;
	}
	
	return 0;
}

 

本文地址:https://blog.csdn.net/C_13579/article/details/109269474