*题解:CF1284C New Year and Permutation

题目链接

解析

首先可以发现框定段 \([l,r]\) 满足如果将该区间内的数从小到大排列,则最终得到的序列连续。

考虑如何求一个给定序列的框定段个数,这其实是 P8600,对正解并没有启发。

正难则反,考虑对于所有长度为 \(x\) 的框定段,包含它的排列个数。段内元素有 \(n - x + 1\) 种选择,段内排列有 \(x!\) 种,段外排列有 \((n - x)!\) 种,段的可选位置有 \(n - x + 1\) 个,全部乘起来即为所求。每个长度的结果加起来即为答案。

时间复杂度 \(O(n)\)

代码

/*
*/
#include <bits/stdc++.h>
#define eps 0.0000000001
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1) | 1) 
#define mid ((l + r) >> 1)
using namespace std;
typedef long long ll;
typedef unsigned ui;
typedef pair<ll, ll> pii;
const int N = 2.5e5 + 5, M = 20, P = 450, mod = 998244353, mod2 = 1e9 + 7, b1 = 131;
int fac[N];
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	int n,m;
	cin>>n>>m;
	fac[0] = 1;
	for(int i=1;i<=n;i++){
		fac[i] = 1ll * fac[i - 1] * i % m;
	}
	int res = 0;
	for(int x=1;x<=n;x++){
		res = (res + 1ll * (n - x + 1) * (n - x + 1) % m * fac[x] % m * fac[n - x] % m) % m;
	}
	cout<<res;
	return 0;
}
posted @ 2026-08-06 19:07  yutar  阅读(7)  评论(0)    收藏  举报