【Wannafly挑战赛9】~D 造一造

我怎么也没想到,还有竟然会这么难,心态爆炸,数学是真正的瓶颈:

首先,这个一看就是大数,

1)其中第一个思想 逆元 ,什么意思呢?

 (1/n)%p 会出现一个大问题,精度问题 ======》 如果设 a = 1/n 呢?

 (1/n)%p = 1*a%p = a/b* b*a %p     哈哈解决 ===

2) 费马小定理

在模为素数p的情况下,有费马小定理   a^(p-1)=1(mod p)

那么a^(p-2)=a^-1(mod p) 也就是说a的逆元为a^(p-2)

而在模不为素数p的情况下,有欧拉定理 a^phi(m)=1(mod m) (a⊥m)

同理a^-1=a^(phi(m)-1)

因此逆元x便可以套用快速幂求得了x=a^(phi(m)-1)

但是似乎还有个问题?如何判断a是否有逆元呢? 

检验逆元的性质,看求出的幂值x与a相乘是否为1即可

PS:这种算法复杂度为O(log2N)在几次测试中,常数似乎较上种方法大

当p比较大的时候需要用快速幂求解

 3)逆元打表时候的小技巧:经典

inv[i] = inv[i+1]*(i+1)%mod;
4. 快速幂 a^b

ll Pow (ll a ,ll b){
	ll  ans =1;
	while(b){
		if(b%2==1)
			ans =ans*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return ans;
}
5)卡特兰数

n个左括号,m个右括号的合法组合 ======>C(n,n+m)-C(n+1,n+m)

 看了半个小时,恍然大悟,就是二分平面,然后上下调整

应用:(注意一定要记笔记 )

1.n个节点构成的二叉树,共有多少种情形?

2.一个栈(无穷大)的进栈序列为1,2,3,…,n,有多少个不同的出栈序列

3.类似问题,买票找零

4.n*n棋盘从左下角走到右上角而不穿过主对角线的走法

5.、求一个凸多边形区域划分成三角形区域的方法数?

6.矩阵连乘的括号化

7.在圆上选择2n个点,将这些点成对连接起来使得所得到的n条线段不相交的方法数?


WYF正试图用一个栈来构造一棵树,现在他已经构造了 n个元素作为树的节点,只要将这 n个元素依次入栈出栈就可以形成一棵树了。当然,这个问题与树并没有关系,所以它叫做 WYF的栈。每次你可以入栈一个新元素或者当栈非空时出栈一个元素, n个元素必须依次入栈,而 WYF希望其中第 m个元素入栈之后,栈中恰好有 k个元素,现在他想知道一共有多少种入栈出栈顺序满足这个条件。

输入描述:

第一行一个正整数T,表示数据组数。(1<=T<=10000)
对于每组数据包含一行三个正整数n,m,k。

输出描述:

 
 
 对于每组数据输出一个正整数表示答案。
 由于答案可能过大,所以只需要输出对10 9+7取模后的答案
示例1

输入

2
3 3 3
3 3 2

输出

1
2
示例2

输入

5
10 3 2
10 2 2
10 7 5
10 6 2
10 7 6

输出

6864
11934
2200
3780
924
示例3

输入

2
5 4 4
5 2 1

输出

5
14

备注:

1<=n,m,k<=106



#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;
#define INF 0x7f 
typedef long long ll ;
#define f(i,l,r) for(int i=l;i<=r;++i)
#define g(i,l,r) for(int i=l;i>=r;--i)
#define mod 1000000007
const int N = 2000000;
ll jc[N+5]={1},inv[N+5]={1};
ll Pow(ll a ,ll b); //a^b
ll Cata(ll a ,ll b); //卡特兰数
ll C( ll n ,ll m);

int main(){
	//阶乘和逆元打表
	f(i,1,2000001)
		jc[i]=jc[i-1]*i%mod;
	//费马小定理
	inv[2000001] = Pow(jc[2000001],mod-2);
	g(i,N,1)
		inv[i] = inv[i+1]*(i+1)%mod;
	int t ; int n,m,k;
	cin>>t;
	while(t--){
		cin>>n>>m>>k;
		cout<<Cata(m-1,m-k)*Cata(n-(m-k),n-m)%mod<<endl;
	}
	return 0;
}
 
ll Pow (ll a ,ll b){
	ll  ans =1;
	while(b){
		if(b%2==1)
			ans =ans*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return ans;
}
ll Cata(ll a ,ll b){
	return (C(a+b,a)-C(a+b,a+1)+mod)%mod;
}
ll C( ll n ,ll m){
	 return  n<m? 0:jc[n]*inv[m]%mod*inv[n-m]%mod;
}


未来的我一定会感谢正在努力的现在的我!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值