前面三题感觉还行,4 5没写出来,暴力打了70%和10%
逆序对这个算法进阶指南有提到~~
逆序对的两种解法:
- 归并排序:cnt +=mid- i+1
- 树状数组:tree的index是数字的值,value是数字出现次数。get(n) - get(a[i])当前数对后面的贡献,get(a[i] - 1)是变为负数后会对前面产生的贡献
4 众数和
一个由1和2组成的数组,求每个区间众数和
input
3
2 1 2
output
9
[2],[2,1,2],[2]的众数是 2.
[2,1],[1],[1,2]的众数是 1.
因此答案是 9.
思路:将1转换为-1,将2转换为+1,使用前缀和的方式来判断一个区间内2的数量是否多于1的数量,从而推导出众数
为了区间和的计算方便,这里采用前缀和来进行处理:
树状数组下标表示当前位置的前缀和值
值表示前缀和值出现的次数
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e6 + 10;
ll t[N];
ll n;
#define debug(x) cout << #x << " = " << x << endl
// tree
ll lowbit(ll x) {
return x & -x;
}
// add
void add(ll x, ll v) {
for (ll i = x; i <= n + n + 1; i += lowbit(i)) {
t[i] += v;
}
}
// get
ll get(ll x) {
ll res = 0;
for (ll i = x; i; i -= lowbit(i)) {
res += t[i];
}
return res;
}
// 1. we can make 1 -> -1, 2 -> 1
// then, [l, r] 的区间和即2-1的数量
// if >0 mean 2的数量多, else 1的数量多
// we can use pre
int main() {
cin >> n;
ll ans = 0, res = 0;
add(n + 1, 1);
for (ll i = 1; i <= n; i++) {
ll tm;
cin >> tm;
if (tm == 1) {
ans -= 1;
} else {
ans += 1;
}
// [-n, n] -> [1, 2n+1]
// res to store the number of 2
res += get(ans + n);
debug(res);
add(ans + n + 1, 1);
}
ll r = n * (n + 1) / 2 - res;
cout << res * 2 + r;
return 0;
}
5 排列
给你一个排列a[n],
她定义f(i)为:将第i个元素取反后,形成的数组的逆序对数量。求f(1)到f(n)的值。排列是指一个长度为n的数组,1到n每个元素恰好出现了一次。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e6 + 10;
#define debug(x) cout << #x << " = " << x << endl
ll t[N], a[N];
ll left_[N], right_[N];
ll n;
ll lowbit(ll x) {
return x & -x;
}
ll get(ll x) {
ll res = 0;
for (int i = x; i; i -= lowbit(i)) {
res += t[i];
}
return res;
}
void add(ll x, ll v) {
for (int i = x; i <= n; i += lowbit(i)) {
t[i] += v;
}
}
// tree
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
cin >> n;
ll ans = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
left_[i] = get(n) - get(a[i]);
ans += left_[i];
add(a[i], 1);
}
memset(t, 0, sizeof t);
for (int i = n; i; i--) {
right_[i] = get(a[i] - 1);
add(a[i], 1);
}
for (int i = 1; i <= n; i++) {
cout << ans - left_[i] - right_[i] + i - 1 << (i == n ? " " : "\n");
}
return 0;
}
本文使用 文章同步助手 同步