Description

\(n \le 2*10^5\)

给定限制序列 \(A\)

求满足 \(P_i\le A_i\) 的所有排列中

逆序对个数的和

Solution

考虑知道一个 \(A\) 序列时怎么计算排列个数

记 \(C[i]\) 表示 \(A\ge i\) 的个数

然后依次决定 \(n, n-1, \cdots 1\) 填在哪里

填 \(k\) 时有 \(C[k]\) 个可选位置, 其中 \(n-k\) 被占用

因此总排列个数为 \(\prod_{k=1}^n C[k]-(n-k)\)

不难证明无解时该式返回0

用期望线性性去统计答案

考虑 \(i < j, P_i>P_j\)

当 \(A_i\le A_j\) 时, 可知 \(P_j\le A_i\), 把 \(A_j\) 改为 \(A_i\), 此时的所有排列中有一半是满足逆序对的

当 \(A_i\gt A_j\) 时, 转为统计 \(P_i<P_j\) 的方案数, 用总的去减这个就好了

注意到修改时把 \((A_j, A_i]\) 的 \(C\) 都减了一, 定义这个是 \(C'\)

按权值从大到小枚举 \(A_j\)

我们要求的是 \(suff[A_i+1] * C'[A_j+1..A_i] * pref[A_j] * sign(j<i)\)

按标号维护线段树, 第一项维护在线段树里, 第二项通过打标记维护

Code

#include <bits/stdc++.h>
using namespace std;
#define ri rd<int>
#define rep(i, a, b) for (int i = (a), _ = (b); i <= _; ++i)
#define per(i, a, b) for (int i = (a), _ = (b); i >= _; --i)
#define For(i, a, b) for (int i = (a), _ = (b); i < _; ++i)
const int maxN = 2e5 + 7;
typedef long long LL;
const LL O = 1e9 + 7; template<class T> T rd() {
bool f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = 0;
T x = 0; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; return f ? x : -x;
} int n;
struct Node {
int v, i;
inline bool operator < (const Node &y) const {
return v > y.v;
}
}a[maxN];
LL c[maxN], d[maxN];
LL C[maxN], sufC[maxN]; namespace Seg {
const int maxN = ::maxN << 1;
struct Node;
typedef Node* node;
struct Node {
node lc, rc;
int l, mid, r;
int sz;
LL sum, tag;
bool havtag;
Node(int _sz = 0, LL _sum = 0) : sz(_sz), sum(_sum) { havtag = false; } Node operator + (const Node &v) const {
return Node(sz + v.sz, (sum + v.sum) % O);
} void totag(LL d) {
(sum *= d) %= O;
if (!havtag) havtag = true, tag = 1;
(tag *= d) %= O;
} void pushdown() {
if (havtag) {
lc->totag(tag);
rc->totag(tag);
havtag = false;
}
}
}*rt, pool[maxN], *tpool = pool; void build(node &x, int l, int r) {
x = tpool++;
x->l = l, x->r = r, x->mid = (l + r) >> 1;
if (l == r) return;
build(x->lc, l, x->mid);
build(x->rc, x->mid+1, r);
} void init() {
build(rt, 1, n);
} void ins(node x, int to, LL d) {
x->sz++;
(x->sum += d) %= O;
if (x->l == x->r) return;
x->pushdown();
if (to <= x->mid) ins(x->lc, to, d);
else ins(x->rc, to, d);
} void ins(int x, LL d) {
ins(rt, x, d);
} Node get(node x, int l, int r) {
if (l <= x->l && x->r <= r) return *x;
x->pushdown();
if (r <= x->mid) return get(x->lc, l, r);
if (x->mid < l) return get(x->rc, l, r);
return get(x->lc, l, x->mid) + get(x->rc, x->mid+1, r);
} Node get(int l, int r) {
if (l > r) return Node();
return get(rt, l, r);
}
} int main() {
#ifndef ONLINE_JUDGE
freopen("a.in", "r", stdin);
#endif n = ri();
rep (i, 1, n) {
c[a[i].v = ri()]++;
a[i].i = i;
} per (i, n, 1) c[i] += c[i+1];
rep (i, 1, n) {
c[i] = c[i] - (n-i);
d[i] = c[i] - 1;
}
sufC[n] = 1; per (i, n-1, 0) sufC[i] = sufC[i+1] * c[i+1] % O;
C[0] = 1; rep (i, 1, n) C[i] = C[i-1] * c[i] % O; Seg::init();
sort(a+1, a+n+1);
LL ans = 0, cnt = 0;
for (int v = n, i = 1; v; --v) {
LL res = 0;
for (; i <= n && a[i].v == v; ++i) {
Seg::Node tp = Seg::get(1, a[i].i-1);
res -= tp.sum;
cnt += tp.sz;
tp = Seg::get(a[i].i+1, n);
res += tp.sum;
Seg::ins(a[i].i, sufC[v]);
}
ans += res % O * C[v] % O;
Seg::rt->totag(d[v]);
}
ans = ans % O * (O+1) / 2 % O;
ans += cnt % O * C[n] % O;
printf("%lld\n", (ans % O + O) % O); return 0;
}

AGC023E - Inversion的更多相关文章

  1. HDU 1394 Minimum Inversion Number ( 树状数组求逆序数 )

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 Minimum Inversion Number                         ...

  2. 控制反转Inversion of Control (IoC) 与 依赖注入Dependency Injection (DI)

    控制反转和依赖注入 控制反转和依赖注入是两个密不可分的方法用来分离你应用程序中的依赖性.控制反转Inversion of Control (IoC) 意味着一个对象不会新创建一个对象并依赖着它来完成工 ...

  3. HDU 1394 Minimum Inversion Number(最小逆序数 线段树)

    Minimum Inversion Number [题目链接]Minimum Inversion Number [题目类型]最小逆序数 线段树 &题意: 求一个数列经过n次变换得到的数列其中的 ...

  4. 依赖倒置原则(Dependency Inversion Principle)

    很多软件工程师都多少在处理 "Bad Design"时有一些痛苦的经历.如果发现这些 "Bad Design" 的始作俑者就是我们自己时,那感觉就更糟糕了.那么 ...

  5. HDU 1394 Minimum Inversion Number(最小逆序数/暴力 线段树 树状数组 归并排序)

    题目链接: 传送门 Minimum Inversion Number Time Limit: 1000MS     Memory Limit: 32768 K Description The inve ...

  6. Inversion Sequence(csu 1555)

    Description For sequence i1, i2, i3, … , iN, we set aj to be the number of members in the sequence w ...

  7. ACM: 强化训练-Inversion Sequence-线段树 or STL·vector

    Inversion Sequence Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%lld & %llu D ...

  8. ACM Minimum Inversion Number 解题报告 -线段树

    C - Minimum Inversion Number Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d &a ...

  9. HDU-Minimum Inversion Number(最小逆序数)

    Problem Description The inversion number of a given number sequence a1, a2, ..., an is the number of ...

随机推荐

  1. 微信小程序CheckBox选中事件

    1.微信小程CheckBox选中问题 <checkbox-group bindchange="checkboxChange" data-index="{{index ...

  2. 【机器学习算法基础+实战系列】SVM

    概述 支持向量机是一种二分类模型,间隔最大使它有别于感知机.支持向量机学习方法由简至繁的模型:线性可分支持向量机(linear support vector machine in linearly s ...

  3. NOI P1896 互不侵犯 状压DP

    题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 注:数据有加强(2018/4/25) ...

  4. Git使用简单总结--源自廖雪峰网站

    创建版本库git add加入到暂存区git commit -m" "加入到分支 时光机穿梭git satus查看仓库的当前状态git diff file 查看修改内容 版本回退HE ...

  5. パラメータID一覧

    名称 内容 ABK 処理グループ. AUF 受注伝票タイプ. AVE FI:支払明細通知書のテンプレート登録. BAR 伝票タイプ. BNK 銀行コード. BUK 会社コード. CAC 管理領域. D ...

  6. 文档-linux io模式及select,poll,epoll

    文档-Linux IO模式详解 1. 概念说明 在进行解释之前,首先要说明几个概念:- 用户空间和内核空间- 进程切换- 进程的阻塞- 文件描述符- 缓存 I/O 1.1 用户空间与内核空间 现在操作 ...

  7. contest0 from codechef

    A  CodeChef - KSPHERES 中文题意  Mandarin Chinese Eugene has a sequence of upper hemispheres and another ...

  8. javascript的js调用

    本来从一开始接触编程开始,自己就一直写后端,但是对于前端真的不会,但是没办法呀,公司要做,所以,好吧,开始了写一写简单的javascript的内容其中,在xxx.jsp页面中出现了这个 <a c ...

  9. PHP.17-文本式留言板

    文本式留言板 思路: 1.首页:index.php  添加/查看信息界面 单纯的表单页面,注意留言内容为文本域<textarea> 2.添加信息页面:doAdd.php 1.获取要添加的留 ...

  10. Postman-CI集成Jenkins(3)

    Postman-CI集成Jenkins(3) Postman-简单使用 Postman-进阶使用 Postman-CI集成Jenkins Newman 官方说明:Postman's command-l ...