珂朵莉的数列
珂朵莉的数列
https://ac.nowcoder.com/acm/problem/14522
离散化,树状数组,大数简单输出
题意:
珂朵莉给了你一个序列,有 个子区间,求出她们各自的逆序对个数,然后加起来输出
输入描述:
第一行一个数 n 表示这个序列 a 的长度
之后一行 n 个数,第i个数表示ai
输出描述:
输出一行一个数表示答案
分析:
树状数组进阶中!!!!!!!!!
这题大佬们已经分析的很清楚了。
考虑贡献,对于一个逆序对(i,j)他在整个计算中的贡献为 : i(n-j+1)
当我们固定j,找到所有与j搭配的i
(i1,j)、(i2,j)、(i3,j)。。。。。。
那么总贡献便为:(i1+i2+i3+......)(n-j+1)
sum(i)*(n-j+1)
这里的这个i是在我们遍历到j之前遍历到的比j大的元素的下标
如此我们可以用树状数组维护!!!!
因为实在是太多了,所以我们离散,排序确定大小关系后重新编号
拿这题坑的就是,他会爆long long
致命、致命
曾在一个大佬的题解那学了一个简单的爆long long 的处理方法
我们用两个long long来存储ans1,ans2
ans2存储1e18的倍数,ans1存储1e18的余数
这样输出的时候我们就先输出ans2再输出ans1,注意ans1输出时要保证长度为18高位补零
代码如下
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
const int max_n = 1e6 + 100;
const ll mx = 1e18;
ll BIT[max_n];
int a[max_n];
int b[max_n];
void renew(int x,int num) {
for (;x < max_n;x += (x & -x))BIT[x] += (ll)num;
}
ll quiry(int x) {
ll res = 0;
for (;x;x -= (x & -x))res += BIT[x];
return res;
}
int main() {
ios::sync_with_stdio(0);
int n;cin >> n;
map<int, int> ls;
for (int i = 1;i <= n;i++)
cin >> a[i], b[i] = a[i];
sort(b + 1, b + 1 + n);
int total = 1;
for (int i = 1;i <= n;i++)
if (ls.find(b[i]) == ls.end())ls[b[i]] = total++;
for (int i = 1;i <= n;i++)
a[i] = ls[a[i]];
ll ans1 = 0;ll ans2 = 0;
for (int i = 1;i <= n;i++) {
ll tmp = quiry(max_n-1) - quiry(a[i]);
ans1 += tmp * ((ll)n - i + 1);
renew(a[i],i);
if (ans1 >= mx) { ans2 += ans1 / mx;ans1 %= mx; }
}
if (ans2) {
cout << ans2;
cout.fill('0');cout.width(18);
cout << ans1 << endl;
}
else cout << ans1 << endl;
}
查看8道真题和解析