[SMOJ1787]逆序对
来源:互联网 发布:淘宝流量钱包不能用了 编辑:程序博客网 时间:2024/06/12 01:40
题目描述
Smart 得到了一个 1~
n 的全排列。Smart 每次会交换第
i 个数和第j 个数,对于每一次交换,Smart 需要 Sarah 回答该全排列的逆序对数为多少。“1、2、3、4、………、248289469!”Sarah 如是回答到。
Smart 觉得答案数太大,不太好判断是否正确,所以只需回答最后答案取模 2 的结果。
输入格式 1787.in
第一行一个整数
n ;第二行为 1~
n 的某个全排列;第三行一个整数
m ,表示交换操作的次数。接下来
m 行,每行两个数i 和j 。
输出格式 1787.out
输出
m 行,每行包含一个整数表示交换后答案。
输入样例 1787.in
1
1 2 3 4
1
1 2
输出样例 1787.out
1
数据范围
30%的数据:
n,m≤1000 ;
100%的数据:n,m≤100000 。
本题看似复杂,但破解了其中的奥妙之后,编码量十分短。
做法一:暴力做
直接按题意模拟,每次交换两个元素重新求逆序对
时间复杂度:取决于求逆序对的算法,两重 for 循环为
得分:30
代码:
#include <algorithm>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>using namespace std;const int maxn = 1e5 + 100;#define lowbit(x) (x & -x)int n, m;int a[maxn];int tree[maxn];void update(int x) { while (x <= n) { tree[x]++; x += lowbit(x); }}int query(int x) { int sum = 0; while (x) { sum += tree[x]; x -= lowbit(x); } return sum;}int calc() { int ans = 0; memset(tree, 0, sizeof tree); for (int i = 1; i <= n; i++) { update(a[i]); ans += i - query(a[i]); } return ans;}int main(void) { freopen("1787.in", "r", stdin); freopen("1787.out", "w", stdout); scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); scanf("%d", &m); for (int i = 0; i < m; i++) { int x, y; scanf("%d%d", &x, &y); swap(a[x], a[y]); printf("%d\n", calc() & 1); } return 0;}
做法二:
算出最初的逆序对数,之后每次交换就将答案取反(0 变 1,1 变 0)
时间复杂度:
得分:100
理由:若每次交换排列中两个不相等的数,必会增加或减少奇数对逆序对。
如何证明?(感谢 oql 的指导)
不妨设被交换的数分别为
于是有两种情况:
为了方便,我们不妨将
首先,A、B、C 每个部分数中(不含
在 A 部分中的数,交换后对逆序对数没有影响。因为虽然
同理,在 C 部分中的数,交换后对逆序对数也没有影响。
于是我们就要考虑 B 部分中的数,分三类讨论:
- 大于
ai 的数,必然也大于aj ,不妨设为x ,易知交换前有逆序对(x,aj) ,交换后有逆序对(x,ai) ,故它们对逆序对数无影响。 - 小于
aj 的数,必然也小于ai ,不妨设为y ,易知交换前有逆序对(ai,y) ,交换后有逆序对(aj,y) ,故它们对逆序对数无影响。 - 小于
ai 而大于aj 的数。不妨设为z ,易知交换前有逆序对(ai,z) 和(z,aj) ,交换后无逆序对。若这样的数有p 个,则逆序对数减少2p 对。
最后,因为
情况二:
参考代码:
#include <algorithm>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>using namespace std;const int maxn = 1e5 + 100;#define lowbit(x) (x & -x)int n, m;int a[maxn];int tree[maxn];void update(int x) { while (x <= n) { tree[x]++; x += lowbit(x); }}int query(int x) { int sum = 0; while (x) { sum += tree[x]; x -= lowbit(x); } return sum;}int calc() { int ans = 0; memset(tree, 0, sizeof tree); for (int i = 1; i <= n; i++) { update(a[i]); ans += i - query(a[i]); } return ans;}int main(void) { freopen("1787.in", "r", stdin); freopen("1787.out", "w", stdout); scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); scanf("%d", &m); int x, y; scanf("%d%d", &x, &y); swap(a[x], a[y]); int ans = calc() & 1; printf("%d\n", ans); for (int i = 1; i < m; i++) { scanf("%d%d", &x, &y); if (x != y) ans = !ans; printf("%d\n", ans); } return 0;}
- [SMOJ1787]逆序对
- 逆序数 & 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- 逆序对
- Mac下搭建php开发环境教程
- Oracle排错总结
- JVM内存模型
- 一款开源的密码管理器
- Oracle中Restore和Recovery的区别
- [SMOJ1787]逆序对
- java时间间隔
- linux下防火墙iptables原理及使用
- RHEL6.5上升级OpenSSH7.4p1
- java 线程锁对象锁的理解
- 452. Minimum Number of Arrows to Burst Balloons
- 让java程序在后台一直执行(例如putty关闭后后台程序继续运行)
- 9.斐波那契数列
- 基于FTP服务器搭建yum源