- 感觉好像没6301难,但是思路特别巧妙。
- 对于一个合法的序列,我们都可以用两个(没有交集)上升子序列将其覆盖,如果已经是有序的话也不影响
- 考虑这个序列的前缀max,我们将那些对前缀max有贡献的位置(就是一个连续段开头)拉出来,一定是一个上升子序列,另一方面,设两个数ai,ai+1,ai对前缀max有贡献,且ai+1对max无贡献(ai+1<ai),那么ai+1后面的数都必须要比ai+1大
- 还有,如果我们确定了前缀max,那么整个序列必定是唯一确定的(因为剩下的只能从小到大一次填入)
- 那我们只要求有多少个max序列
- 考虑它的性质,maxi<=maxi+1,maxn=n,i<=maxi
- 放到平面上就是求(1,1)到(x,y)再由(x,y)走到(n,n)且不能过y=x-1这条线,翻折法即可。
- (a,b)这个点表示在a这个位置,当前前缀max是b,因为我们第一个数不一定是1,但是我们可以先走到(1,2),(1,3)这些点,然后再走过去,相当于分别以1,2,3开头,又因为1,1到这些点的方案只有一个,故这样做是对的。
- code
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++)
#define fd(i,b,a) for (int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int N=20000000+5;
typedef long long ll;
const ll mo=1000000007;
ll inv[N],fac[N],ans1,ans2;
int n,m,x,y;
void R(int &x){
int t=0; char ch;
for (ch=getchar();!('0'<=ch&&ch<='9');ch=getchar());
for (;('0'<=ch&&ch<='9');ch=getchar())t=t*10+ch-'0';
x=t;
}
ll C(ll x,ll y){
if (x<y) return 0;
return fac[x]*inv[x-y]%mo*inv[y]%mo;
}
ll power(ll a,ll b){
ll t=1ll,y=a%mo;
while (b){
if (b&1) t=t*y%mo;
y=y*y%mo;
b/=2;
}
return t;
}
ll F(ll x){
return (x%mo+mo)%mo;
}
int main(){
freopen("tg.in","r",stdin);
freopen("tg.out","w",stdout);
int T;
R(T);
fac[0]=1;inv[0]=1;
fo(i,1,N-1) fac[i]=fac[i-1]*(ll)i%mo;
inv[N-1]=power(fac[N-1],mo-2);
fd(i,N-2,1) inv[i]=inv[i+1]*(ll)(i+1)%mo;
while (T--){
R(n);R(x);R(y);
if (x>y) swap(x,y);
x--; y--; n--;
ans1=F(C(x+y,x)-C(y+x,y+1));
ans2=F(C(2*n-x-y,n-x)-C(2*n-x-y,n-y-1));
printf("%lld\n",ans1*ans2%mo);
}
}