题目传送门

  传送门

题目大意

  (相信大家都知道)

  显然要考虑一个排列$p$合法的充要条件。

  考虑这样一个构造$p$的过程。设排列$p^{-1}_{i}$满足$p_{p^{-1}_i} = i$。

  • 初始令$q = (1, 2, \cdots, n)$。
  • 依次考虑$i = 1, 2, \cdots, n$。
    • 设$x = p_i$,如果$q^{-1}_x > i$,那么交换$q_x, q_{x - 1}$。

  上述算法每次交换的时候会使逆序对增加1。

  考虑给出的下界,假设交换的是$i$和$i + 1$。

  不难用归纳法证明$p_i \leqslant i$。

  那么考虑$ \Delta = (i + 1 - p_i + |p_{i + 1} - i|) - (i - p_i + |p_{i + 1} - i - 1|)$。

  • 如果$p_{i + 1} \geqslant i + 1$,那么有$ \Delta = (i + 1 - p_i + p_{i + 1} - i) - (i - p_i + p_{i + 1} - i - 1) =2$
  • 如果$p_{i + 1} \leqslant i$,那么有$\Delta = (i + 1 - p_i + i - p_{i + 1}) - (i - p_i + i + 1 - p_{i + 1}) = 0$

  每次改变量要么为0,要么为2,如果某一次为0,那么将永远达不到下界。

  因此序列合法当仅当上述算法中,每次交换满足$q_x \geqslant x$。

  上述算法中,未确定的数并且可以向前移动的是一段后缀,并且满足$q_x = x$。

  假如某次将$y$向前移动,那么如果一个$z < y$,并且$z$未确定,那么你不能将$z$向前移动。

  然后考虑一下没有字典序限制怎么做,显然这个问题不会更难。

  设$f_{i, j}$表示考虑到排列的前$i$个数,其中最大值为$j$。

  转移考虑最大值有没有发生改变。

  $(i, j)$是平面上的一个点,考虑把这个问题转化到平面上。

  最大值改变等于可以向上走若干步,不变相当于向右走一步。

  另外还需要满足$i \geqslant j$。

  用折线法可以轻松计算出方案数。

  然后我们来考虑原问题。

  字典序严格大于似乎有点烦?考虑小于等于。(其实是我今天想的时候把题意记错了,写完发现过不了样例)

  仍然考虑枚举一个长度为$i - 1$的前缀,然后计算在$i$脱离限制后的方案数。

  下面只考虑长度为$i - 1$的前缀是合法的情况。

  • 如果$a_{i}$是一个前缀最大值,那么考虑$i - 1$的前缀最大值是$mx$,答案加上从$(i, mx), (i, mx + 1), \cdots, (i, a_i - 1)$开始的方案数。
  • 如果$a_i$不是前缀最大值
    • 如果比不是前缀最大值的最小值还大,那么此时前缀$i$不合法,答案加上从$(i, mx)$开始的方案书。
    • 否则对答案没有贡献。

Code

/**
* loj
* Problem#2719
* Accepted
* Time: 652ms
* Memory: 10236k
*/
#include <bits/stdc++.h>
using namespace std;
typedef bool boolean;
#define ll long long void exgcd(int a, int b, int& x, int& y) {
if (!b) {
x = 1, y = 0;
} else {
exgcd(b, a % b, y, x);
y -= (a / b) * x;
}
} int inv(int a, int n) {
int x, y;
exgcd(a, n, x, y);
return (x < 0) ? (x + n) : (x);
} const int Mod = 998244353; template <const int Mod = :: Mod>
class Z {
public:
int v; Z() : v(0) { }
Z(int x) : v(x){ }
Z(ll x) : v(x % Mod) { } friend Z operator + (const Z& a, const Z& b) {
int x;
return Z(((x = a.v + b.v) >= Mod) ? (x - Mod) : (x));
}
friend Z operator - (const Z& a, const Z& b) {
int x;
return Z(((x = a.v - b.v) < 0) ? (x + Mod) : (x));
}
friend Z operator * (const Z& a, const Z& b) {
return Z(a.v * 1ll * b.v);
}
friend Z operator ~(const Z& a) {
return inv(a.v, Mod);
}
friend Z operator - (const Z& a) {
return Z(0) - a;
}
Z& operator += (Z b) {
return *this = *this + b;
}
Z& operator -= (Z b) {
return *this = *this - b;
}
Z& operator *= (Z b) {
return *this = *this * b;
}
friend boolean operator == (const Z& a, const Z& b) {
return a.v == b.v;
}
}; Z<> qpow(Z<> a, int p) {
Z<> rt = Z<>(1), pa = a;
for ( ; p; p >>= 1, pa = pa * pa) {
if (p & 1) {
rt = rt * pa;
}
}
return rt;
} typedef Z<> Zi; typedef class Input {
protected:
const static int limit = 65536;
FILE* file; int ss, st;
char buf[limit];
public: Input():file(NULL) { };
Input(FILE* file):file(file) { } void open(FILE *file) {
this->file = file;
} void open(const char* filename) {
file = fopen(filename, "r");
} char pick() {
if (ss == st)
st = fread(buf, 1, limit, file), ss = 0;//, cerr << "str: " << buf << "ed " << st << endl;
return buf[ss++];
}
} Input; #define digit(_x) ((_x) >= '0' && (_x) <= '9') Input& operator >> (Input& in, unsigned& u) {
char x;
while (~(x = in.pick()) && !digit(x));
for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0');
return in;
} Input& operator >> (Input& in, unsigned long long& u) {
char x;
while (~(x = in.pick()) && !digit(x));
for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0');
return in;
} Input& operator >> (Input& in, int& u) {
char x;
while (~(x = in.pick()) && !digit(x) && x != '-');
int aflag = ((x == '-') ? (x = in.pick(), -1) : (1));
for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0');
u *= aflag;
return in;
} Input& operator >> (Input& in, long long& u) {
char x;
while (~(x = in.pick()) && !digit(x) && x != '-');
int aflag = ((x == '-') ? (x = in.pick(), -1) : (1));
for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0');
u *= aflag;
return in;
} Input in (stdin); const int N = 6e5 + 5;
const int N2 = N << 1; int T, n;
Zi fac[N2], _fac[N2]; void init_fac(int l, int r) {
for (int i = l; i <= r; i++) {
fac[i] = fac[i - 1] * i;
}
_fac[r] = ~fac[r];
for (int i = r; i > l; i--) {
_fac[i - 1] = _fac[i] * i;
}
}
void init_fac(int n) {
static int old = 0;
fac[0] = 1, _fac[0] = 1;
if (n > old) {
init_fac(old + 1, n);
old = n;
}
}
Zi comb(int n, int m) {
return (n < m) ? (0) : (fac[n] * _fac[m] * _fac[n - m]);
} Zi C(int x, int y) {
return comb(x + y, x);
}
Zi S(int x, int y) {
if (y + 1 <= x)
return 0;
return (y == n) ? (1) : (C(n - x, n - y) - C(n + 1 - x, n - 1 - y));
} boolean vis[N];
int main() {
freopen("inverse.in", "r", stdin);
freopen("inverse.out", "w", stdout);
in >> T;
while (T--) {
in >> n;
if (!n) {
puts("0");
continue;
}
init_fac(n << 1);
memset(vis, false, n + 2);
int mx = 0, sc = 1, i = 1, a;
Zi ans = 0;
for (i = 1; i < n; i++) {
in >> a;
if (a > mx) {
for (int j = mx; j < a; j++) {
ans += S(i, j);
}
mx = a;
} else {
while (vis[sc]) sc++;
if (sc ^ a) {
ans += S(i, mx);
break;
}
}
vis[a] = true;
}
if (i == n) {
in >> a;
ans += 1;
} else {
while (++i <= n)
in >> a;
}
ans = S(0, 0) - ans;
printf("%d\n", ans.v);
}
return 0;
}

最新文章

  1. 【基于WinForm+Access局域网共享数据库的项目总结】之篇一:WinForm开发总体概述与技术实现
  2. 2016年我们重新思考移动互联网创业的风险, 微信还是APP?
  3. PHP基于数组的分页函数(核心函数array_slice())
  4. 文件和目录:access函数
  5. glut64位操作系统安装
  6. 在JSP中使用jQuery的冲突解决(收集整理)
  7. css中的img和input标签
  8. System.Drawing.Design.UITypeEditor自定义控件属性GetEditStyle(ITypeDescriptorContext context),EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
  9. Mac通过以太网共享网络
  10. VC Windows系统服务创建代码
  11. IDEA第五章----Git常用技能
  12. 学习---&gt;更新集合/内存/深浅拷贝
  13. 【C++ Primer | 15】虚继承
  14. 集合01_List
  15. python Console menu
  16. A*寻路初探(转载)
  17. Ajax:HyperText/URI, HTML, Javascript, frame, frameset, DHTML/DOM, iframe, XMLHttp, XMLHttpRequest
  18. javaScript 变量提升 var let const,以及JS 的解析阶段和执行阶段
  19. javascript 全选 反选 js代码
  20. 统计无向图中三角形的个数,复杂度m*sqrt(m).

热门文章

  1. WEB测试应该注意哪些地方,怎样才能做好WEB测试
  2. h5py报错:FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.
  3. appstore-react v2.0—redux-actions和redux-saga的应用
  4. c# 调用接口返回json
  5. webform的原生操作图片预览和上传
  6. Java面向对象——相关基本定义
  7. SpringBoot+vue整合websocket
  8. git合并单个节点
  9. Mac下安装npm全局包提示权限不够
  10. springBoot添加日志管理