题目背景
本题时空限制已经扩大
题目描述
人比人,气死人;鱼比鱼,难死鱼。小鱼最近参加了一个“比可爱”比赛,比的是每只鱼的可爱程度。参赛的鱼被从左到右排成一排,头都朝向左边,然后每只鱼会得到一个整数数值,表示这只鱼的可爱程度,很显然整数越大,表示这只鱼越可爱,而且任意两只鱼的可爱程度可能一样。由于所有的鱼头都朝向左边,所以每只鱼只能看见在它左边的鱼的可爱程度,它们心里都在计算,在自己的眼力范围内有多少只鱼不如自己可爱呢。请你帮这些可爱但是鱼脑不够用的小鱼们计算一下。
和之前的要求不一样,比赛组委会关心的是这个排列的“总得意值”。一共有 n 只小鱼,总共有 n×(1+n)/2 个不同的区间。每个区间的得意值等于这个区间中符合“左边的一只鱼的可爱值比右边的一只鱼可爱值更大”的对数(其实就是区间逆序对数啦)。总得意值就是所有区间的“得意值”的和。现在要求输出“总得意值”是多少。
输入输出格式
输入格式:
第一行输入一个整数 n,表示鱼的数目。
第二行内输入 n 个整数,用空格间隔,依次表示从左到右每只小鱼的可爱程度。
输出格式:
输出一个整数表示答案。
输入输出样例
输入样例#3: 复制
20
6 0 4 5 8 8 0 6 6 1 0 4 6 6 0 0 7 2 0 5
输出样例#3: 复制
3481
思路
小鱼比可爱我记得好像是个红题,为啥就加了一个括号,带上升级版就红的发紫了。。。
这题是个正常人都会想到逆序对,让后看了一下数据范围,这题是要杀人啊。这什么范围。。。。对出题人表示强烈的谴责。。。
考虑一组逆序对(a[i],a[j])(a[i],a[j])贡献了几次,不难发现贡献了i*(n - j + 1)i∗(n−j+1)次。
考虑怎么统计,通常求逆序对我们是让树状数组上的值+1+1,现在我们实际上只要把+1+1改成+(n - j + 1)+(n−j+1)就行了(想想乘法分配律就知道这是对的)。
那么接下来就是常规的离散化加树状数组
要是想满分要用int 128
但好像noip 不给用就没改,就放个60分的吧
1 #include<iostream>
2 #include<cstdio>
3 #include<algorithm>
4 using namespace std;
5 const int maxn=1000010;
6 long long n,a[maxn],b[maxn],c[maxn],tot,ans,f[maxn];
7 int lowbit(long long x)
8 {
9 return x&(-x);
10 }
11 void update(long long x,long long y)
12 {
13 while(x<=n)
14 {
15 c[x]+=y;
16 x+=lowbit(x);
17 }
18 }
19 int query(long long x)
20 {
21 long long ans=0;
22 x--;
23 while(x)
24 {
25 ans+=c[x];
26 x-=lowbit(x);
27 }
28 return ans;
29 }
30 int main()
31 {
32 cin>>n;
33 for(int i=1;i<=n;i++)
34 {
35 cin>>a[i];
36 b[i]=a[i];
37 }
38 sort(b+1,b+1+n);
39 int tot=unique(b+1,b+1+n)-b-1;
40 for(int i=1;i<=n;i++)
41 {
42 f[i]=lower_bound(b+1,b+tot+1,a[i])-b;
43 }
44 for(int i=n;i>=1;i--)
45 {
46 long long i1=i;
47 long long i2=n-i+1;
48 ans+=(long long )(i1*query(f[i]));
49 update(f[i],i2);
50 }
51 cout<<ans<<endl;
52 return 0;
53 }