JZOJ6395 消失的序列

題目大意

有一個長度爲nn的序列,其中元素爲1 n1~n的排列,其中第pospos位的元素爲xx,問有多少種合法的序列是有規則的.
有規則的序列被定義爲,如果利用一個棧可以將這個序列排成升序,那麼這個序列就是有規則的.
n<=1e6n<=1e6

solution

如果將入棧操作設爲’(’,將出棧操作設爲’)'的話,那麼序列可以變成一個長度爲2n2n的括號序列.
並且根據題意,第pospos個左括號顯然會和第xx個右括號相配對.
那麼我們枚舉第pospos個左括號所在的位置,設爲ii.
顯然ii的左邊有pos1pos-1個左括號和iposi-pos個右括號,這是一個走格子的問題,可以用組合數解決.
那麼我們就可以根據這些信息算出與第pospos個左括號匹配的右括號(也就是第xx個右括號)的位置.
而這兩個括號中間顯然就是長度爲2(xi+pos1)2*(x-i+pos-1)的括號序,就是一個卡特蘭數.
有了這些信息,第xx個右括號右邊的括號數量就可以得出了,同樣是一個走格子問題,用組合數解決即可.
注意要判方案的合法性.

#include <cstdio>
#include <algorithm>
#include <cstring>
#define ll long long

using namespace std;

const int N = 2e6 + 5,mo = 1e9 + 7;

int n,pos,x;
ll ans;
ll inv[N],frac[N];

void prepare()
{
	inv[0] = inv[1] = 1;
	for (int i = 2 ; i < N ; i++) inv[i] = (mo - mo / i) * inv[mo % i] % mo;
	for (int i = 2 ; i < N ; i++) inv[i] = inv[i - 1] * inv[i] % mo;
	frac[0] = frac[1] = 1;
	for (int i = 2 ; i < N ; i++) frac[i] = frac[i - 1] * i % mo;
}

ll C(int m,int n)
{
	return frac[n] * 1LL * inv[m] % mo * inv[n - m] % mo;
}

ll solve(int n,int m)
{
	if (n < 0 || m < 0) return 0;
	return ((C(m,n + m) - C(m - 1,n + m)) % mo + mo) %mo;
}

int main()
{
	freopen("stack.in","r",stdin);
	freopen("stack.out","w",stdout);
	scanf("%d%d%d",&n,&pos,&x);
	prepare();
	for (int i = pos ; i <= (pos << 1) - 1 ; i++)
	{
		int restl = n - pos - (x - i + pos - 1),restr = n - x;
		ll s1 = solve(x - i + pos - 1,x - i + pos - 1),s2 = solve(pos - 1,i - pos),s3 = solve(restr,restl);
		ans = (ans + s1 * s2 % mo * s3 % mo) % mo;
	}
	printf("%lld\n",ans);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章