- 园题链接
- 应老师要求找一道组合计数
- 被之前的卡特兰数误导了,写了半天满江红(qwq)
题面
求出长度为(n),且由(1->n)构成的,单调不上升序列和单调不下降序列总个数(不能重复)
做法
设这个数列为(a)
既然直接求(a)的个数很困难,那么就换一个方向考虑,于是(LH)大佬很快想到了差分数组
设(a)的差分数组为(b),看来(sum_{i=1}^{n}{b_i})就等于(a_n-a_1),枚举(a_n-a_1),求出(b)数组,(b)数组的个数正是(a)数组的个数
这里我枚举的是(a_1)(其实(a_1=b_1)的啦),默认(a_n=n),所以用插板法可以求出(b)数组个数
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define N 3001000
#define mod 1000000007
using namespace std;
ll n,m,inv[N],s[N],ans;
ll ksm(ll x,ll k){
ll tmp=1;
while(k){
if(k%2==1)tmp*=x,tmp%=mod;
x=x*x%mod;
k/=2;
}
return tmp;
}
//c(a,b)
ll C_c(ll a,ll b){
if(b<a)return 0;
if(a==0)return 1;
if(b==0)return 0;
return s[b]*inv[b-a]%mod*inv[a]%mod;
}
int main(){
cin>>n;
s[0]=1;
for(ll i=1;i<=2*n;i++){
s[i]=s[i-1]*i%mod;
inv[i]=ksm(s[i],mod-2);
}
for(ll i=0;i<n;i++){
ans+=C_c(n-1,2*n-i-1);
ans%=mod;
}
cout<<(ans-n+mod+1)%mod;
}
想必大家发现了,我们最后输出的东西和上面讲的不太相符,上面的思路理应只包含单调不上升序列和单调不下降序列其中之一
最后答案应该是(ans*2-n)
然后由于本人太菜,打不出正确的做法,结果误打误撞用这个过了(qwq)
解释一下为什么会这样
既然我们枚举了(a_1),那么剩下的(b_i)的和就是(n-a_1)是吧
但是组合数里使用的却是(2*n-a_1-1),手玩一下发现正好比(n-a_1)多一
就是说这个数列不再只是由(1->n)个数组成的了,而变成了(1->n+1)
也就是说,这个代码求出的是一个长度为(n),却由(1->n+1)组成的……序列
让我们手玩一下(n=3)的情况(下面展示的是(a)数组的取值)
1 1 1
1 1 2
1 1 3
1 2 2
1 2 3
1 3 3
2 2 2
2 2 3
2 3 3
3 3 3
后面对称的不写了
而若再使用n+1,会多出来这些可行取值
1 1 4
1 2 4
1 3 4
1 4 4
2 2 4
2 3 4
2 4 4
4 4 4
正好就是对称的数列-1
所以误打误撞直接输出(ans-n-1)就可(注意把(4 4 4)去掉)