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;
}