艾瑞题解
- 园题链接
- 应老师要求找一道组合计数
- 被之前的卡特兰数误导了,写了半天满江红\(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\)去掉)