JYZdalao上课讲了这道题,觉得很好可做
其实也是一道理解了就水爆了的题目
把题意抽象化,可以发现题目求的满足
i<j
a[i]>=j
a[j]>=i
的i,j对数。由于i,j顺序问题,可以在不考虑i,j顺序的情况下将ans>>1
如果题目只要求前两个条件,那就是求逆序对的个数,树状数组即可
但是这里还要求a[j]>=i,因此我们先把a排序一遍,然后把所有小于i的全部弹出
剩下的就是树状数组水一水了
注意a[i]=min(a[i],n+1)(太大了要爆内存,也没有离散化的必要)
CODE
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=2e5+5;
struct data
{int x,num;
}a[N];
int s[N],n,now;
long long ans,tree[N];
inline char tc(void)
{static char fl[100000],*A=fl,*B=fl;return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{x=0; char ch=tc();while (ch<'0'||ch>'9') ch=tc();while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
}
inline int min(int a,int b)
{return a<b?a:b;
}
inline bool comp(data a,data b)
{return a.x<b.x;
}
inline int lowbit(int x)
{return x&(-x);
}
inline void add(int x,int y)
{while (x<=n+1){tree[x]+=y;x+=lowbit(x);}
}
inline long long get(int x)
{long long res=0;while (x){res+=tree[x];x-=lowbit(x);}return res;
}
int main()
{register int i;//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);read(n);for (i=1;i<=n;++i){read(s[i]); s[i]=min(s[i],n+1);a[i].x=s[i]; a[i].num=i; add(i,1);}sort(a+1,a+n+1,comp);for (now=1,i=1;i<=n;++i){while (now<=n&&a[now].x<i) add(a[now++].num,-1);ans+=get(s[i]);if (i<=s[i]) --ans;}printf("%lld",ans>>1);return 0;
}