艾瑞题解

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

posted @ 2020-09-19 11:01  蒟蒻丁  阅读(32)  评论(0编辑  收藏  举报