CF 961E Tufurama

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;
}
原文地址:https://www.cnblogs.com/cjjsb/p/8734578.html