多校第十场——1004 Permutation Counting

Problem Description
For a given permutation a1,a2,⋯,an of length n, we defined the neighbor sequence b of a, the length of which is n−1, as following:

bi={01ai<ai+1ai>ai+1

.

For example, the neighbor sequence of permutation 1,2,3,6,4,5 is 0,0,0,1,0.

Now we give you an integer n and a sequence b1,b2,⋯,bn−1 of length n−1, you should calculate the number of permutations of length n whose neighbor sequence equals to b.

To avoid calculation of big number, you should output the answer module 109+7.

Input
The first line contains one positive integer T (1≤T≤50), denoting the number of test cases. For each test case:

The first line of the input contains one integer n,(2≤n≤5000).

The second line of the input contains n−1 integer: b1,b2,⋯,bn−1

There are no more than 20 cases with n>300.

Output
For each test case:

Output one integer indicating the answer module 109+7.

Sample Input
2
3
1 0
5
1 0 0 1

Sample Output
2
11

题意:
给一个只包含0、1,长度维n - 1的数组b,
b[i] = 1 表示a[i] > a[i + 1]
b[i] = 0 表示a[i] < a[i + 1]
a数组是1~n的一个排列,问有多少种a数组。

思路:
在这里插入图片描述

代码:

#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
const int N = 5e3 + 5;
const ll mod = 1e9 + 7;
ll dp[N][N];
ll x[N], y[N];
int T, n, a;
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> T;
	while (T--)
	{
		cin >> n;
		for (int i = 0; i <= n; ++i)
		{
			for (int j = 0; j <= n; ++j)
			{
				dp[i][j] = 0;
				if (i + j == n - 1)
					dp[i][j] = 1;
			}
		}
		for (int i = 2; i <= n; ++i)
		{
			y[0] = dp[n - i + 1][0], x[0] = dp[0][n - i + 1];
			for (int r = 1; r <= n - i + 1; ++r)
			{
				y[r] = (dp[n - i + 1 - r][r] + y[r - 1]) % mod;
				x[r] = (dp[r][n - i + 1 - r] + x[r - 1]) % mod;
			}
			cin >> a;
			if (a)
			{
				for (int l = 0, r = n - i; l <= n - i; ++l, --r)
				{
					dp[l][r] = (dp[l][r] + y[n - i + 1] - y[r]) % mod;
				}
			}
			else
			{
				for (int l = 0, r = n - i; l <= n - i; ++l, --r)
				{
					dp[l][r] = (dp[l][r] + x[n - i + 1] - x[l] + mod) % mod;
				}
			}
		}
		dp[0][0] = (dp[0][0] % mod + mod) % mod;
		cout << dp[0][0] << endl;
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>