String
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 ).
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
【思路分析】
个人感觉这个题目的重点不是整数唯一分解定理,而是推导的过程。网上所有的题解差不多都是转换为二维坐标里面的方法,特别巧妙,值得反复揣测,由于都是别人的思路,在这里就不赘述了。最终推导出的结果是:C(n+m,m) - C (m+n,m-1)。
将上式结果展开,得到: (n+1-m)*(n+m)! / (m! *(n+1)!) ,n和m的范围为0到1000000,直接递归求解的话肯定会T,因此这里需要利用整数唯一分解定理进一步化简。
首先可以根据素数筛法找到不超过(n + m)之内的素数并存到数组prime中,然后对于每一个素数prime[i]再去和(n + 1 - m)、(n+m)!、m!、(n+1)!这四项相除直到得到最终的次幂cnt,再将prime[i]的cnt次幂这个结果存在ans中,即 ans *= prime[i] ^ cnt(注意取模的情况),循环完prime数组中所有的素数后便可以得到最终的结果。
代码如下:
2
【思路分析】
个人感觉这个题目的重点不是整数唯一分解定理,而是推导的过程。网上所有的题解差不多都是转换为二维坐标里面的方法,特别巧妙,值得反复揣测,由于都是别人的思路,在这里就不赘述了。最终推导出的结果是:C(n+m,m) - C (m+n,m-1)。
将上式结果展开,得到: (n+1-m)*(n+m)! / (m! *(n+1)!) ,n和m的范围为0到1000000,直接递归求解的话肯定会T,因此这里需要利用整数唯一分解定理进一步化简。
首先可以根据素数筛法找到不超过(n + m)之内的素数并存到数组prime中,然后对于每一个素数prime[i]再去和(n + 1 - m)、(n+m)!、m!、(n+1)!这四项相除直到得到最终的次幂cnt,再将prime[i]的cnt次幂这个结果存在ans中,即 ans *= prime[i] ^ cnt(注意取模的情况),循环完prime数组中所有的素数后便可以得到最终的结果。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1000005;
const int mod = 20100501;
bool isPrime[maxn * 2];
int prime[maxn * 2];
int len,n,m;
ll ans;
void getPrime(int n)//筛素数
{
len = 0;
memset(isPrime,1,sizeof(isPrime));
isPrime[0] = isPrime[1] = 0;
for(int i = 2;i <= n;i++)
{
if(isPrime[i])
{
prime[len++] = i;
for(int j = 2 * i;j <= n;j += i)
{
isPrime[j] = 0;
}
}
}
}
int getNum(int p,int n)//计算n!内有多少个p相乘
{
int num = 0;
while(n)
{
n /= p;
num += n;
}
return num;
}
void init()
{
ans = 1;
scanf("%d %d",&n,&m);
}
void solve()
{
int nm = n + 1 - m;
for(int i = 0;i < len && prime[i] <= (n + m);i++)//素数最大到(n + m)
{
int cnt = 0;
while(nm % prime[i] == 0)//计算nm的素数的幂次
{
nm /= prime[i];
cnt++;
}
cnt += getNum(prime[i],n + m) - getNum(prime[i],m) - getNum(prime[i],n + 1);
//整个式子的prime[i]的幂次
for(int j = 1;j <= cnt;j++)
{
ans *= prime[i];
if(ans >= mod)
ans %= mod;
}
}
printf("%I64d\n",ans);
}
int main()
{
int t;
scanf("%d",&t);
getPrime(2 * maxn);
while(t--)
{
init();
solve();
}
return 0;
}