离散化,树状数组,大数简单输出
题意:
珂朵莉给了你一个序列,有 个子区间,求出她们各自的逆序对个数,然后加起来输出
输入描述:
第一行一个数 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; }