中国石油大学OJ 第五场个人训练赛 小奇遐想

问题 M: 小奇遐想

时间限制: 1 Sec  内存限制: 128 MB
提交: 421  解决: 106
[提交] [状态] [讨论版] [命题人:admin]

题目描述

撷来一缕清风飘渺
方知今日书信未到
窗外三月天霁垂柳新长枝条
风中鸟啼犹带欢笑
——《清风醉梦》
小奇望着青天中的悠悠白云,开始了无限的遐想,在它的视野中,恰好有n朵高度不同的白云排成一排,他想从左到右选出四朵白云a,b,c,d,使得h_a<h_b<h_d<h_c,即看起来像是彩虹的形状!它想知道有多少种方案数。

输入

第一行包括1个整数n。
第二行包括n个整数,第i个正数表示h_i,保证这n个整数是n的一个全排列。

输出

输出一个整数表示答案。(mod 16777216)

样例输入

5
1 5 3 2 4

样例输出

0

提示

对于10%的数据n<=600;对于40%的数据n<=5000;
对于100%的数据n<=200000。

题解:询问1243的种类数,问题可以转换成12xx-1234,预处理每个位置的数字左边比它小的数字的个数L[i]和右边比它大的数字的个数R[i],那么12xx就可以枚举每个位置然后L[i]*C(2,R[i]),求和即可。1234则枚举3的位置让树状数组处理12的个数*r[i]求和即可。

其中树状数组预处理左边比它小的个数,访问到每个数字的时候在a[i]处add(1)即可,然后每次query(a[i])就是左边比它小的数字的个数。对于1234来说就直接对于每个位置add(a[i],l[i]),每个数字将左边的1的个数用树状数组维护

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=16777216;
const int maxn=1e6+7;
ll a[maxn],n;
ll tree[maxn],lmin[maxn],rmin[maxn];

void add(int x,ll val)
{
    for(int i=x;i<=n;i+=i&-i)
        tree[i]+=val;
}

ll query(int x)
{
    ll ans=0;
    for(int i=x;i;i-=i&-i)
        ans+=tree[i];
    return ans;
}

void make_wen()
{
    for(int i=1;i<=n;i++)
    {
        lmin[i]=query(a[i]);
        rmin[i]=a[i]-lmin[i]-1;
        add(a[i],1);
    }

    ll tot=0;
    for(int i=1;i<=n;i++)
        tot=(tot+lmin[i]*(n-i-rmin[i])*(n-i-rmin[i]-1)/2)%mod;

    memset(tree,0,sizeof(tree));
    ll res=0;
    for(int i=1;i<=n;i++)
    {
        res=(res+query(a[i])*(n-i-rmin[i])%mod)%mod;
        add(a[i],lmin[i]);
    }

    printf("%lld\n",(tot-res+mod)%mod);
}
int main()
{
    cin>>n;

    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);

    make_wen();
}

猜你喜欢

转载自blog.csdn.net/sudu6666/article/details/81281554