题意:序列是一个数组,由n个从1到n不同的数字组成,我们可以从序列b中得到一个子序列a,子序列的两个端点为[l,r],是连续的,对于一个序列,其中的数字为p1,p2,p3,p4....,pn,如果给定一个端点[l, r],如果\(\max\{p_l, p_{l+1}, \dots, p_r\} - \min\{p_l, p_{l+1}, \dots, p_r\} = r - l\),那么我们称之为\(framed segments\),我们定义一个序列p的幸福度为这个序列中\(framed segments\)的个数。给定两个整数n,m,计算长度为n的序列中\(framed segments\)的个数,然后对这个个数对m取余。

分析:这是一道组合数学题,我们可以巧妙地去枚举长度为n的数列,我们可以换个角度,不去枚举所有的生成排列,我们可以去枚举子序列,假设我们枚举了一个长度为len的子序列,这个序列中的最大值和最小值相减为这个子序列的长度,这个子序列中数字的全排列为len的阶乘,然后这个子序列的最大值和最小值在整个长度为n的序列中,有n - len + 1种选法,然后我们再对这个长度为n的数列中的剩下数字全排列,那么就有!(n - len + 1)种排列方式,那么我们就可以得到整个公式为\((n - i + 1) * frac[i] * (frac[n - i + 1])\),对于阶乘,我们可以预处理出来,如果还是不懂,可以画下图,很快就明白了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
using LL = long long;
const int N = 250005;

LL frac[N];
int main()
{
	LL n, mod;
	scanf("%lld%lld", &n, &mod);

	frac[0] = 1;
	//0的阶乘 == 1
	for (int i = 1; i <= n; ++i)
		frac[i] = frac[i - 1] * i % mod;

	//剩余数n - i + 1的顺序
	LL ans = 0;
	for (int i = 1; i <= n; ++i)
	{
		ans += (n - i + 1) * (frac[i] * frac[n - i + 1] % mod);
		ans %= mod;
	}

	cout << ans << endl;

	return 0;
}