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

60 篇文章 1 订阅
44 篇文章 0 订阅

地址: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。

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

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

下面讲一下怎么求,

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

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

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

即路径数为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;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值