2022ICPC网络赛第二场 - G. Good Permutation
组合数学 + 树形DP + 单调栈
题目详情 - G Good Permutation (pintia.cn)
题意
对于一个 的排列 ,有 个限制
-
每个限制给定一组下标 , 满足
-
这 个区间只有不相交和完全包含两种关系
求满足上述条件的排列个数
思路
-
区间最大 - 区间最小 == 区间长度 - 1,意味着这个长度为 len 的区间就是连续 len 个数的排列
-
因为区间没有相交的情况,结合第一条,容易想到可以递归子问题求解
-
设大区间为结点 ,它完全包含的各个小区间为结点 , 共有 tot 个,则
意思是把子区间用捆绑法当作是一个点,则一共有 个点,它们可以任意排列,再乘子区间内部的答案即可
- 现在考虑如何建树,可将区间按左端点递增,右端点递减排序并去重,用单调栈维护当前大区间的右端点(从栈底到栈顶变小),枚举第 个区间时
- 如果其左端点 > 大区间右端点,则当前大区间无法包括第 i 个区间,要 pop 出来,直到当前栈顶的大区间能够包含区间 i
- 把当前区间压栈
注意结构体用 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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南