牛客IOI周赛18-提高组 C-山脉 题解
排列
https://ac.nowcoder.com/acm/contest/7225/A
考虑枚举山峰的最右边位置 ,那么 ~ 是一个不下降序列, ~ 也是个不下降序列。
考虑一个最大高度为 的不下降序列的方案数,做一下差分,那么有若干个位置不为 ,且这些位置的总和为 ,那么相当于将 分给这 个位置,由于数字都大于 ,所以第一个位置的差分值至少为 ,所以实际上是将 分给 个位置,方案数就是个插板法 。
答案就是:
后面那个部分是求杨辉三角一列的和,套公式得到:
改一下:
考虑化简里面的部分,其实里面就是在求:
这有点像一个卷积的形式,考虑生成函数,设 。
那么上面那个式子求出来的,其实就是 卷 的第 项系数,即
所以 ,代入到上面的式子,得到:,这个就是答案了。
代码如下:
#include <cstdio> #define maxn 15000010 #define mod 1000000007 int T,n,m; int ksm(int x,int y){int re=1;for(;(y&1?re=1ll*re*x%mod:0),y;y>>=1,x=1ll*x*x%mod);return re;} int fac[maxn],inv_fac[maxn]; void work(){ fac[0]=inv_fac[0]=1; for(int i=1;i<=maxn-10;i++)fac[i]=1ll*fac[i-1]*i%mod; inv_fac[maxn-10]=ksm(fac[maxn-10],mod-2); for(int i=maxn-11;i>=1;i--)inv_fac[i]=1ll*inv_fac[i+1]*(i+1)%mod; } void add(int &x,int y){x=(x+y>=mod?x+y-mod:x+y);} int C(int x,int y){ if(x<y)return 0; return 1ll*fac[x]*inv_fac[y]%mod*inv_fac[x-y]%mod; } int main() { work(); scanf("%d",&T);while(T--) { scanf("%d %d",&m,&n);int ans=0; for(int i=1;i<=m;i++)add(ans,C(n+2*i-3,n-1)); printf("%d\n",ans); } }