Educational Codeforces Round 41 (Rated for Div. 2) _E. Tufurama

大家如果有能力的话,可以看一下当时比赛页面中的题解,当然了题解大部分都会是英文的,比如这个题的首先打开这道题:http://codeforces.com/contest/961/problem/E,然后我们在下面可以看到这个东西:

Educational Codeforces Round 41 (Rated for Div. 2) _E. Tufurama_第1张图片

那么这个就是题解了,点进去就可以看到这次题的所有题解以及正确的程序,当然Codeforces上的所有程序以及测试样例也都是公开的,大家也可以在一下大神们的程序,看一下能不能看明白......

我们现在就来看一下这个题,他的题意就是我们要寻找这样的数对,满足:a[i]>=j && a[j]>=i && i

程序参考:https://blog.csdn.net/my_sunshine26/article/details/79831362

我们首先要保证满足我们的第二个条件即a[j] >= i,我们在输入的时候去寻找满足a[j] >= i的最大的i,(j是我们当前的位置)我们设这个最大的数值为x,那么在x位置之前的数都是满足这个条件的,我们只需要在x位置之前找a[i] >= j的数就可以了,这样我们就可以用到我们的树状数组,来求解前面有多少个比j大的数字了,后面这个过程实质就是求逆序数的过程,那么这个题就是在前面处理的时候有点难理解

这个题就思路就是这样,但是写出程序来就很不容易理解,理解了好长时间

第一个我们要做的优化是    a[i] = min(a[i],n)   因为,如果存在a[i]> n,但是我们是不会存在另一个条件的,因为数组最大下标就是n

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

typedef long long ll;
const int maxn = 200005;
//a[i]>=j&&a[j]>=i的有序对< i , j >的对数(ivec[maxn];
ll tree[maxn];

ll lowbit(ll x)
{
    return x&(-x);
}

ll query(int pos)
{
    ll ans=0;
    while(pos)
    {
        ans+=tree[pos];
        pos-=lowbit(pos);
    }
    return ans;
}

void update(int pos,ll val)
{
    while(pos n)
        //vec[满足条件 i<= a[j]的最大下标].push_back[i];
        vec[min((ll)i-1,a[i])].push_back(i);//这里push_back的i实际上是我们上面谁的j,前面的是i
    }
    //vec里面储存的是在这个位置下是我们满足 i <= a[j] 条件中有哪些 j 的位置的最大值
    //开始计算满足条件的 a[i] >= j 的条件
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        update(a[i],1);    //首先在 a[i] 的位置上开始插  1
        for(int j = 0; j < vec[i].size();j ++)   
            ans += query(n) - query(vec[i][j]-1);
    }
    printf("%lld\n",ans);
}
前面的处理很难想到,还是要多做一些题了,多了解一些算法.....



你可能感兴趣的:(Codeforces)