String


Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2305    Accepted Submission(s): 668


Problem Description


Recently, lxhgww received a task : to generate strings contain '0's and '1's only, in which '0' appears exactly m times, '1' appears exactly n times. Also, any prefix string of it must satisfy the situation that the number of 1's can not be smaller than the number of 0's . But he can't calculate the number of satisfied strings. Can you help him?


 



Input


T(T<=100) in the first line is the case number.
Each case contains two numbers n and m( 1 <= m <= n <= 1000000 ).


 



Output


Output the number of satisfied strings % 20100501.


 



Sample Input


1 2 2


 



Sample Output


2


/*
HDOJ 3398 组合数学+N!质因数分解
汗!不会。
卡特兰数 1大于0的个数
①:我们设初始在坐标系的原点(0,0),从字符串第一位开始,碰到一个1就向上走,碰到一个0就向右走,
那么由n个1、m个0组成的字符串最后必定走到(n,m)点,
即满足由n个1、m个0组成的字符串的个数为C(n+m,n)=C(n+m,m) (满足n+m长度内n个长度走1或者m个长度走0)。

②:对于任意前缀中1的个数不少于0的个数的字符串的个数这个条件,可以看成是坐标系中,
从(0,0)点走到(m, n)点,并且跟y=x-1这条直线不相交的方案数。又因为(0,0)点关于直线y=x-1的对称点是(1,-1),
而从(1,-1)点走到(m, n)点的所有方案一定都会与直线y=x-1相交,
对于这些方案,将从(1,-1)点到与y=x-1的第一个交点之间的路径关于y=x-1对称翻转过去,
就可以得到所有不满足题意的从(0,0)点走到(m, n)点的方案,C(n+m,m-1)=C(n+m,n+1) 为什么n+1
于是最终答案就是C(n+m, n)-C(n+m,n+1)。

接下来就是求上式子模20100501的值,因为n、m很大,所以我们利用质因数分解来分解阶乘,
然后分子分母抵消指数最后求指数幂的和即可,但是这样做还是会TLE。
而用对于阶乘,有很多非常好的性质可以利用(不利用就TLE。。。),下面介绍N!的质因数分解,
也就是求N!中x的幂,首先因为N! = 1*2*3*……*N,所以N!中x的幂就是各个数质因数分解后x的幂之和,
考虑含1,2,……,N中含x^1的共有x^1,2*x^1,……,y*x^1共y个,其中y=floor(N/x^1),
而含x^2的共有x^2,2*x^2,……,y*x^2共y个,其中y=floor(N/x^2)=floor((N/x)/x),
所以可以利用递归来计算N!中x的幂

C(n+m, n)-C(n+m,n+1)=(n+m)!/(n+m-1)!n!-(n+m)!/(n+m-1)!(n+1)!
=(n+1-m)(n+m)!/(n+1)!m!
power定理分解素数,对于每个素数分别算幂,取模相乘即可。
*/
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
#define N 1000001
typedef __int64 LL;
int f[N*2+1],prime[N*2+1],k;

/*
8!/2
8/2=4 4/2=2 2/2=1
第1轮 2 4 6 8 含有2的 4
第2轮 1 2 3 4 含有2的 2
第3轮 1 2 含有2的 1
数字:2 4 6 8
1 2 1 3=7
*/
int cal(int p,int n)//计算n!是素数p的幂次
{
int ans=0;
while(n)
{
n/=p;
ans+=n;
}
return ans;
}

void calPrime()
{
memset(f,0,sizeof(f));
k=0;
for(int i=2;i<=N*2;i++)
{
if(f[i])
continue;
prime[k++]=i;
for(int j=i*2;j<=N*2;j+=i)
f[j]=1;
}
}

int main()
{
int t,n,m,i;
calPrime();
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
LL ans=1;
int nm=n-m+1;
for(i=0;i<k&&prime[i]<=n+m;i++)
{
int cnt=0;
while(nm%prime[i]==0)//计算n-m+1的素数的幂
{
nm/=prime[i];
cnt++;
}
//计算整个公式的素数的幂
int ipow=cnt+cal(prime[i],n+m)-cal(prime[i],n+1)-cal(prime[i],m);
for(int j=1;j<=ipow;j++)
{
ans=(ans*prime[i])%20100501;
}
}
printf("%I64d\n",ans);
}
return 0;
}