Educational Codeforces Round 156 (Rated for Div. 2) D. Monocarp and the Set(组合数学 插空法)

题目

对于一个未确定的长为n的排列a(2<=n<=3e5),

一开始写下一个长为n-1的串,每个字母有?,<,>三种可能

第i(1<=i<=n-1)个字母,

①为<,表示a[i+1]是[1,i+1]的最大值

②为<,表示a[i+1]是[1,i+1]的最小值

③为?,表示a[i+1]既不是[1,i+1]最大值也不是最小值

m(m<=3e5)次修改,每次选一个位置x(1<=x<=n-1),将这个位置原来的字母改成?,<,>的某一个

询问修改前的满足限制的合法排列数,

以及每次修改后满足限制的合法排列数

思路来源

jiangly代码

题解

不看不会,一看秒会

注意到,如果i在[1,i-1]已经确定好的排列里插空,

也就是确定了相对大小,那么排列是唯一确定的

这个插空的思想,以下这类dp是一类经典题:

CCPC-Wannafly Winter Camp Day4 G.置置置换/hdu4055 Number String(dp/波浪排列)_波浪排列计数-CSDN博客

如果第一个字母既不是最大值也不是最小值,无解,

因为前两个数字一定一个是最大值一个是最小值

从第二个字母开始,比如到第i个字母,需要决定第i+1个值的大小关系时,

[1,i]总共有i+1个空,其中最大值、最小值各对应一个空,方案唯一空,而?对应i-1个空

所以,维护从第二个字母开始?方案的乘积,最大最小方案都唯一

修改时除掉原来的,乘上新改的,

询问时,先判断第一个字母是不是最大最小值的一个,不是输出0,

否则输出从第二个字母开始?方案的乘积

代码

#include
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<

你可能感兴趣的:(组合数学(容斥原理),组合数学,插空法)