2022ICPC网络赛第二场 - G. Good Permutation

组合数学 + 树形DP + 单调栈

题目详情 - G Good Permutation (pintia.cn)

题意

对于一个 \([1,n]\;(1<=n<=10^6)\) 的排列 \(p\),有 \(m\;(1<=m<=10^6)\) 个限制

  1. 每个限制给定一组下标 \(l,r\), 满足 \(max(p_l,p_{l+1},...,p_r)-min(p_l,p_{l+1},...,p_r)=r-l\)

  2. \(m\) 个区间只有不相交完全包含两种关系

求满足上述条件的排列个数

思路

  1. 区间最大 - 区间最小 == 区间长度 - 1,意味着这个长度为 len 的区间就是连续 len 个数的排列

  2. 因为区间没有相交的情况,结合第一条,容易想到可以递归子问题求解

  3. 设大区间为结点 \(u\),它完全包含的各个小区间为结点 \(v_i\), 共有 tot 个,则 \(ans_u=\prod ans_{v_i}*(len_u-\sum len_{v_i}+tot)!\)

意思是把子区间用捆绑法当作是一个点,则一共有 \(len_u-\sum len_{v_i}+tot\) 个点,它们可以任意排列,再乘子区间内部的答案即可

  1. 现在考虑如何建树,可将区间按左端点递增,右端点递减排序并去重,用单调栈维护当前大区间的右端点(从栈底到栈顶变小),枚举第 \(i\) 个区间时
    1. 如果其左端点 > 大区间右端点,则当前大区间无法包括第 i 个区间,要 pop 出来,直到当前栈顶的大区间能够包含区间 i
    2. 把当前区间压栈

注意结构体用 unique 函数要重载 ==

代码

#include <bits/stdc++.h>
using namespace std;
#define endl "\n"

typedef long long ll;
typedef pair<int, int> PII;

const int N = 1e6 + 10;
const int mod = 1e9 + 7;
int n, m;

struct Seg
{
	int l, r;
	bool operator<(const Seg &x) const
	{
		if (l == x.l)
			return r > x.r;
		return l < x.l;
	}
	bool operator==(const Seg &x) const
	{
		return l == x.l && r == x.r;
	}
};
vector<Seg> c;
stack<int> stk;
vector<vector<int> > G(N);
ll fac[N];
void add(int u, int v)
{
	G[u].push_back(v);
}

ll dfs(int u)
{
	ll ans = 1;
	int sum = c[u].r - c[u].l + 1;
	for (int v : G[u])
	{
		sum -= c[v].r - c[v].l + 1;
		ans = ans * dfs(v) % mod;
	}
	return ans * fac[sum + G[u].size()] % mod;
}

void presolve(int n)
{
	fac[0] = 1;
	for (int i = 1; i <= n; i++)
		fac[i] = fac[i-1] * i % mod;
}
int main()
{
	scanf("%d%d", &n, &m);
	presolve(n);
	c.push_back({1, n});
	for (int i = 1; i <= m; i++)
	{
		int l, r;
		scanf("%d%d", &l, &r);
		c.push_back({l, r});
	}
	sort(c.begin(), c.end());
	c.erase(unique(c.begin(), c.end()), c.end());
	m = c.size();
	stk.push(0);
	for (int i = 1; i < m; i++)
	{
		while(!stk.empty() && c[i].l > c[stk.top()].r)
			stk.pop();
		add(stk.top(), i);
		stk.push(i);
	}
	cout << dfs(0) << endl;
    return 0;
}
posted @ 2022-09-27 20:15  hzy0227  阅读(108)  评论(4编辑  收藏  举报