Wannafly挑战赛9 D - 造一造

链接:https://www.nowcoder.com/acm/contest/71/D
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

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

输入描述:

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

输出描述:

 对于每组数据输出一个正整数表示答案。
 由于答案可能过大,所以只需要输出对109+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<=10^6

题解

找规律。

可以把过程分成两个阶段,答案是两个阶段的方案数乘积。

第一阶段:压入第$m$个元素时,刚好有$k$个元素在栈中,这样的状态停止的方案数记为$A$,显然$A$只和$m$和$k$有关,和$n$无关。

第二阶段:有$k$个元素在栈中,还剩$n-m$个元素未压入,将栈弹空为止的方案数记为$B$。

写个暴力可以发现两个阶段的方案数存在同一套规律,可以看代码中最后的注释部分。

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
LL p = 1e9 + 7;

const int maxn = 3e6 + 10;
LL f[maxn];

//******************************
//返回d=gcd(a,b);和对应于等式ax+by=d中的x,y
long long extend_gcd(long long a,long long b,long long &x,long long &y)
{
  if(a==0&&b==0) return -1;//无最大公约数
  if(b==0){x=1;y=0;return a;}
  long long d=extend_gcd(b,a%b,y,x);
  y-=a/b*x;
  return d;
}
//*********求逆元素*******************
//ax = 1(mod n)
long long mod_reverse(long long a,long long n)
{
  long long x,y;
  long long d=extend_gcd(a,n,x,y);
  if(d==1) return (x%n+n)%n;
  else return -1;
}

LL C(LL n, LL m) {
  long long A = f[n];
  long long B = f[n - m] * f[m] % p;
  long long C = mod_reverse(B, p);
  return A * C % p;
}

LL work(LL n, LL m) {
  if(n == m) return 1;
  return (C(n * 2 - m - 1, n - m)
          - C(n * 2 - m - 1, n - m - 1)
          + p) % p;
}

int main() {
  f[0] = 1;
  for(long long i = 1; i < maxn; i ++) {
    f[i] = (f[i - 1] * i) % p;
  }
  int T;
  scanf("%d", &T);
  while(T --) {
    LL n, m, k;
    scanf("%lld%lld%lld", &n, &m, &k);
    if(m > n || m < k) {
      printf("0\n");
      continue;
    }
    LL A = work(m, k);
    LL B = work(n + k + 1 - m, k + 1);
    LL ans = A * B % p;
    printf("%lld\n", ans);
  }
  return 0;
}
/*
 
 A:
 ---+-----------------------------------
 m\k|   1    2    3    4    5    6    7
 ---+-----------------------------------
 1  |   1
 2  |   1    1
 3  |   2    2    1
 4  |   5    5    3    1
 5  |  14   14    9    4    1
 6  |  42   42   28   14    5    1
 7  | 132  132   90   48   20    6    1
 
 B:
 n = 1
 ---+-----------------------------------
 m\k|   1    2    3    4    5    6    7
 ---+-----------------------------------
 1  |   1
 2  |
 3  |
 4  |
 5  |
 6  |
 7  |
 
 n = 2
 ---+-----------------------------------
 m\k|   1    2    3    4    5    6    7
 ---+-----------------------------------
 1  |   2
 2  |   1    1
 3  |
 4  |
 5  |
 6  |
 7  |
 
 n = 3
 ---+-----------------------------------
 m\k|   1    2    3    4    5    6    7
 ---+-----------------------------------
 1  |   5
 2  |   2    3
 3  |   1    1    1
 4  |
 5  |
 6  |
 7  |
 
 n = 4
 ---+-----------------------------------
 m\k|   1    2    3    4    5    6    7
 ---+-----------------------------------
 1  |   14
 2  |   5    9
 3  |   2    3    4
 4  |   1    1    1   1
 5  |
 6  |
 7  |
 
 n = 5
 ---+-----------------------------------
 m\k|   1    2    3    4    5    6    7
 ---+-----------------------------------
 1  |   42
 2  |   14  28
 3  |   5    9   14
 4  |   2    3    4    5
 5  |   1    1    1    1    1
 6  |
 7  |
 
 */

 

posted @ 2018-02-03 10:17  Fighting_Heart  阅读(366)  评论(0编辑  收藏  举报