链接:https://ac.nowcoder.com/acm/contest/881/E
来源:牛客网
题目描述
Bobo has a string of length 2(n + m) which consists of characters `A` and `B`. The string also has a fascinating property: it can be decomposed into (n + m) subsequences of length 2, and among the (n + m) subsequences n of them are `AB` while other m of them are `BA`.
Given n and m, find the number of possible strings modulo (109+7)(109+7).
输入描述:
The input consists of several test cases and is terminated by end-of-file. Each test case contains two integers n and m. * 0≤n,m≤1030≤n,m≤103 * There are at most 2019 test cases, and at most 20 of them has max{n,m}>50max{n,m}>50.
输出描述:
For each test case, print an integer which denotes the result.
示例1
输入
复制
1 2 1000 1000 0 0
输出
复制
13 436240410 1
题目大意:有n+m个A和n+m个B求有多少个字符串满足子序列可以分解为n个AB和m个BA。
解题思路:首先可以想到答案就是所有的排列减去不合法的排列。
ans=C(2*(n+m),n+m)-不合法的。
问题的关键在于如何求不合法的字符串的数量。
对于一个字符串我们肯定贪心的让前边的A和B组成AB 让后边的A结合前边的B。
对于一个字符串如果把A的值设为1,B的值设为-1做前缀和
例如:
AABBBBAA
1 2 1 0 -1 -2 -1 0
结合问题发现 前缀和满足[-m,n];
即X为A的个数 Y为B的个数 X-Y属于[-m,n];
满足这个要求的都是合法的字符串。
那么不合法的字符串有多少个呢?
把不和发的字符串分为两类
第一类一前缀和出现X-Y<-m的
第二类是前缀和出现X-Y>n的。
下面的推导过程和卡特兰数的推导过程几乎一致。
设第一次出现前缀和为 -(m+1)的位置为i(不管后边怎么组合,这个字符串已经是不合法的了),则我们把前i个A变成
B,B变成A。
则当前字符串含有n+m+m+1个A,n+m-(m+1)个B。
这个字符串必会出现前缀和为m+1的情况假设位置为j。
我们将前j个字符取反,就得到了原字符串。
所以我们就建立了新的字符串与旧的字符串的一一对应关系,并且新的字符串的个数是好算的。
对于这样的字符串有多少个呢?
C(2*(n+m),n-1)个。所以满足X-Y<-m的字符串的个数有这么多个。
仿照这个思路可以可以求出第二类的字符串有多少个。
上述的关键在于将一类不好求的问题进行映射,得到一个好求的。
以上思路参考:博客
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 4005;
const int mod = 1e9+7;
LL c[N][N];
void init()
{
c[0][0]=1;
for(int i=1;i<=4000;i++)
{
c[i][0]=1;
for(int j=1;j<=i;j++)
{
c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
}
}
LL C(int x,int y)
{
return c[x][y];
}
int main()
{
int n,m;
init();
while(cin>>n>>m)
{
LL ans=C(2*(n+m),n+m);
if(n)ans=(ans-C(2*(n+m),n-1)+mod)%mod;
if(m)ans=(ans-C(2*(n+m),m-1)+mod)%mod;
printf("%lld\n",(ans+mod)%mod);
}
}