注意:
有的时候memset会出问题
思路:
i代表A,j代表B,题目要求n个AB,m个BA,所以在一个字符串中,前n个A贡献给AB中的A,前m个B贡献给BA中的B,这里用到贪心的思想
所以当i<=n时,直接用于贡献给AB中的A,当i>n时,i-n个A用来组成BA,因此当j>i-n时,此时可以放A组成BA,例如当j=3,i-n=2时,可以再放一个A组成3个BA,dp[i+1][j]=dp[i+1][j]+dp[i][j];同理,当i>j-m时,可以放B组成BA;最后不要忘了%mod.
代码:
#include<iostream> using namespace std; const int maxn = 2005; const int mod = 1e9+7; int dp[maxn][maxn]; int main(){ int n,m; while(cin>>n>>m){ for(int i=0;i<=n+m;i++) for(int j=0;j<=n+m;j++) dp[i][j]=0; dp[0][0]=1; for(int i=0;i<=n+m;i++){ for(int j=0;j<=n+m;j++){ if(j+n>i) dp[i+1][j] = (dp[i+1][j]+dp[i][j])%mod; if(i+m>j) dp[i][j+1] = (dp[i][j+1]+dp[i][j])%mod; } } cout<<dp[n+m][n+m]<<endl; } return 0; }
方法二:
我们要从(0,0)点出发到达(n+m,n+m)并在要求的运动区域内的运动路径不同的个数;
两条直线:y>x-n x>y-m;所围成的粉红色区域就是可以运动的区域
y=x-(n+1)所代表的绿色直线就是y=x-n向右移动一格的直线,只要经过这条直线那么就代表不符合要求中的一种情况,另一种情况:y=x+(m+1),所以我们用c[2*(n+m)][n+m]-符合要求的就是答案
不符合要求的(m-1)+(n+m)+(n-1)中取(m-1)+c[2*(n+m)][n-1];
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
const int maxn = 4e3+5;
typedef long long ll;
ll a[maxn][maxn];
int main(){
int n,m;
a[0][0]=1;
for(int i=1;i<=4004;i++){//一旦大于等于4005就会段错误
a[i][0] = 1;a[i][i] =1;
for(int j=1;j<i;j++){
a[i][j] = (a[i-1][j-1]+a[i-1][j])%mod;
}
}
while(cin>>n>>m){
cout<<(a[2*(n+m)][n+m]-(a[2*(n+m)][m-1]+a[2*(n+m)][n-1])%mod+mod)%mod<<endl;
}
return 0;
}