【问题描述】
小沐在在奥数课上刚学习了组合数C(n,m),以及与组合数相关的一个最重要内容——杨辉三角形。如下图所示的是一个7行的杨辉三角形。
小沐把杨辉三角形从左到右的每列依次编号为0,1,2,……,从上到下的每行编号为0,1,2,……。那么杨辉三角形的第i行第j列的数就是C(i,j)。
现在小沐在思考这样的问题:给出任意n,i,j,那么在n行的杨辉三角形中第i行与第j列的和分别是多少?由于小沐还小,需要你来帮助他解决这个问题。
【输入格式】
第一行是整数T,表示数据组数,
接下来的T行,每行包含3个整数:n ,i ,j ( i, j < n),表示询问n行的杨辉三角形中第i行的和与第j列的和。
【输出格式】
输出有T行,每行输出两个整数,分别为对应输入的n行杨辉三角形的第i行的和以及第j列的和,他们可能很大,请模1004535809后输出。
【输入样例】
3
7 1 0
5 4 3
6 3 2
【输出样例】
2 7
16 5
8 20
【数据范围】
对于50%的数据, 1 <= n <= 5000。
对于100%的数据,T<=100,1<=n<=1000000。
题解:
简单(?)的数论题
一问:杨辉三角形的第i行的和
ans1=2^i
证明一:
很明显第i行的和是第i-1行的和的2倍,且第0行(注意编号从0开始)的和为1
具体说一说:
1. 设d[i][j]为杨辉三角形第i行第j列的数,sum[i]为杨辉三角形第i行的和,则
sum[i]=d[i][0]+d[i][1]+…+d[i][i];
2.在杨辉三角形中,有d[i][j]=d[i-1][j-1]+d[i-1][j],且d[i][0]=d[i][i]=1,所以
sum[i]=d[i][0]+d[i][1]+…+d[i][i]
=d[i-1][0]+(d[i-1][0]+d[i-1][1])+…+(d[i-1][i-2]+d[i-1][i-1])+d[i-1][i-1]
=2*(d[i-1][0]+d[i-1][1]+…+d[i-1][i-2]+d[i-1][i-1]
=2*sum[i-1]
证明二:
二次项定理 (x+y)^n=C(n,0)* x^n+C(n,1)* (x^(n-1))*y+…+C(n,n)*y^n
当x=y=1时,有
2^n=C(n,0)+C(n,1)+…+C(n,n)
也就是杨辉三角形第n行的和
二问:杨辉三角形的第j列的和
ans2=C(n,j+1) (注意n是杨辉三角形的行数,j是编号)
证明:
在杨辉三角形中,有d[i][j]=d[i-1][j-1]+d[i-1][j],且d[i][i]=d[i+1][i+1]=1,所以
d[j][j]+d[j+1][j]+…+d[n-1][j] (再说一次编号是0~n-1)
=d[j+1][j+1]+d[j+1][j]+…+d[n-1][j]
=d[j+2][j+1]+d[j+2][j]+…+d[n-1][j]
=d[j+3][j+1]+d[j+3][j]+…+d[n-1][j]
……
=d[n-1][j+1]+d[n-1][j]
=d[n][j+1]
数据规模达到100000,打表不可能了,只有用组合公式算
最后代码实现的时候由于要取模,且公式里有除法,有两种处理方式:
1.分子分母分解质因数,变成形如 a1^q1*a2^q2*…*an^qn 的形式,用指数相减的方式来计算
2.乘法逆元
其中方法1可行的原因是组合数一定为整数,如果除不尽是不能这样处理的
方法2一定要先打一个阶乘的表出来,否则有可能超时
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdlib>
using namespace std;
typedef long long ll;
const int maxn=1000005,mo=1004535809;
ll jie[maxn]={0};
int n,I,J;
int in(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-f;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
ll mypow(int a,int q){
ll ret=1,tmp=a;
while(q){
if(q&1) ret=ret*tmp%mo;
q/=2,tmp=tmp*tmp%mo;
}
return ret;
}
int main(){
int T=in();
ll ans1,ans2,tmp1,tmp2,tmp3;
jie[0]=jie[1]=1;
for(int i=2;i<=1000001;i++) jie[i]=jie[i-1]*i%mo;
while(T--){
n=in(),I=in(),J=in();
ans1=mypow(2,I);
tmp1=jie[J+1],tmp2=jie[n],tmp3=jie[n-J-1];
tmp1=mypow(tmp1,mo-2),tmp3=mypow(tmp3,mo-2);
ans2=tmp2*tmp3%mo*tmp1%mo;
printf("%lld %lld\n",ans1,ans2);
}
return 0;
}