SPOJ COWPIC(逆序对变形题)

SPOJ COWPIC

题目链接

题意:一个序列,相邻可以交换,问最少交换几次使得变成循环的1-n的其中一种

思路:对于原来正常的变换成1-n而言,答案就是逆序对了,而多了这么一个变形,其实只需要考虑一下,先求出变换成1-n的逆序对,然后如果原序列变成2, 3, 4 ... n, 1的话,等于是在原来的序列上,把每个数字模1加n之后求逆序对,那么对于这个新序列而言,只有原来最大的n变成了1会受影响,那么最大的n原来的逆序对就不在是逆序对,原来不是逆序对的就变成逆序对了,所以只要一开始记录下每个数字的位置,然后在循环一遍,求出对应每个数字+1变成1之后,会增加减少的逆序对统计出来,不断维护最小值即可

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 100005;
typedef long long ll;

#define lowbit(x) (x&(-x))

int bit[N];

void add(int x, int v) {
	while (x < N) {
		bit[x] += v;
		x += lowbit(x);
	}
}

int get(int x) {
	int ans = 0;
	while (x) {
		ans += bit[x];
		x -= lowbit(x);
	}
	return ans;
}

int n, c[N], pos[N];

int main() {
	while (~scanf("%d", &n)) {
		for (int i = 1; i <= n; i++) {
			scanf("%d", &c[i]);
			pos[c[i]] = i;
		}
		ll ans = 0;
		for (int i = 1; i <= n; i++) {
			ans += i - 1 - get(c[i]);
			add(c[i], 1);
		}
		ll ans2 = ans;
		for (int i = 1; i <= n; i++) {
			ans2 -= pos[i] - 1;
			ans2 += n - pos[i];
			ans = min(ans, ans2);
		}
		printf("%lld\n", ans);
	}
	return 0;
}
时间: 2024-10-21 12:24:49

SPOJ COWPIC(逆序对变形题)的相关文章

poj 2299 Ultra-QuickSort 逆序对模版题

用树状数组求逆序对 唯一的坑点就是sum要用long long存 直接贴代码了 以后忘了还能直接看 2333…… PS:和hdu3743代码是一样的,因为两个都是逆序对模版题…… 1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 int s[500005]; 6 int N; 7 struct num{ 8 int xuhao,num; 9 }n

hdu1394Minimum Inversion Number树状数组求逆序对水题

//ans[i]=ans[i-1]+(n+1)-2*num[i] //num[i]为输入时的数据 //ans[i]为m=i时的逆序数 //用树状数组求ans[0]的逆序对 #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn=5010; int num[maxn]; int tree[maxn]; int lowbit(int i) { retu

POJ-3067 Japan---树状数组逆序对变形

题目链接: https://vjudge.net/problem/POJ-3067 题目大意: 日本岛东海岸与西海岸分别有N和M个城市,现在修高速公路连接东西海岸的城市,求交点个数. 解题思路: 记每条告诉公路为(x,y), 即东岸的第x个城市与西岸的第y个城市修一条路.当两条路有交点时,满足(x1-x2)*(y1-y2) < 0.所以,将每条路按x从小到达排序,若x相同,按y从小到大排序. 然后按排序后的公路用树状数组在线更新,求y的逆序数之和 即为交点个数. 比如样例 1 42 33 23

[USACO17FEB] Why Did the Cow Cross the Road I P (树状数组求逆序对 易错题)

题目大意:给你两个序列,可以序列进行若干次旋转操作(两个都可以转),对两个序列相同权值的地方连边,求最少的交点数 记录某个值在第一个序列的位置,再记录第二个序列中某个值 在第一个序列出现的位置 ,求逆序对数量即可 本以为是一道逆序对水题,结果被卡了20分.看了题解才恍然大悟,实际上,序列可以旋转 ≠ 序列成环,由于逆序对的特殊性(并不适用于环),故不能把一个序列单独旋转看成它们的相对移动,正着旋转一个序列≠反着旋转另一个序列(更详细证明可以看洛谷) 所以我们要对两个序列再反着进行一次同样的操作

【权值线段树】离散化介绍 (+利用 线段树 求逆序对)

先介绍一下离散化 桶排大家应该知道,就是开一个数组(下标为数值,记录了该数值的出现次数)然后遍历过去如果出现次数不为零,那就输出这些数字,理论时间复杂度可以达到O(N)但是由于内存限制,不能开很大的数组. 然而 如果某个数列中的数字不要求大小确定,只要求这些数字有相对的大小就够了的话,离散化就有了用武之地 举个例子:数列 3 8 7 5 2000000000000000 我们发现有几个数之间差距很大,但是我们用不到数值的大小,只要求相对大小,那怎么办呢? 观察下面的数列: 1 4 3 2 5 真

P1393 动态逆序对

题目 P1393 动态逆序对 做题前写篇博客是个好方法 做法 题目规定仅有删除,给每个位置标个号,逆序对+时间轴,显然这是个三维偏序 很久没做过\(cdq\)了,就当模板题讲一下: 按删除的先后顺序为关键字排序分治,然后在\(cdq\)中按位置排序,同时前部分删除的时间<=后部分删除时间 此时前部分删除的一个点会影响到的贡献在后部分处理:1.位置大值小查询-值大数量:2.位置小值大查询-值小数量 My complete code #include<cstdio> #include<

P1966 火柴排队——逆序对(归并,树状数组)

P1966 火柴排队 很好的逆序对板子题: 求的是(x1-x2)*(x1-x2)的最小值: x1*x1+x2*x2-2*x1*x2 让x1*x2最大即可: 可以证明将b,c数组排序后,一一对应的状态是最大的: ac+bd<ad+bc ac-ad<bc-bd a*(c-d)<b*(c-d)//c-d<0 a>b(???) 逆序对合并时一定要加等号!!要判断q1是否超出mid!!!(爆零体验): 归并写法 #include<cstdio> #include<cs

2014 HDU多校弟五场A题 【归并排序求逆序对】

这题是2Y,第一次WA贡献给了没有long long 的答案QAQ 题意不难理解,解题方法不难. 先用归并排序求出原串中逆序对的个数然后拿来减去k即可,如果答案小于0,则取0 学习了归并排序求逆序对的方法,可以拿来当模板 TVT 贴代码了: 1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <math.h> 5 #include <iostream&g

水题 逆序对 NOIP 2013 火柴排队

题目如下 题目描述 Description 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度.现在将每盒中的火柴各自排成一列,同一列火柴的高度互不相同,两列火柴之间的距离定义为:,其中 ai表示第一列火柴中第 i 个火柴的高度,bi表示第二列火柴中第 i 个火柴的高度.每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小.请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997 取模的结果. 输入描述 Inp