Tokitsukaze and Strange Inequality

题目链接:https://codeforces.com/contest/1677/problem/A
描述

Tokitsukaze has a permutation p of length n. Recall that a permutation p of length n is a sequence p1,p2,…,pn consisting of n distinct integers, each of which from 1 to n (1≤pi≤n).
She wants to know how many different indices tuples [a,b,c,d] (1≤a<b<c<d≤n) in this permutation satisfy the following two inequalities:
pa < pc and pb > pd.
Note that two tuples [a1,b1,c1,d1] and [a2,b2,c2,d2] are considered to be different if a1≠a2 or b1≠b2 or c1≠c2 or d1≠d2.

输入

The first line contains one integer t (1≤t≤1000) — the number of test cases. Each test case consists of two lines.
The first line contains a single integer n (4≤n≤5000) — the length of permutation p.
The second line contains n integers p1,p2,…,pn (1≤pi≤n) — the permutation p.
It is guaranteed that the sum of n over all test cases does not exceed 5000.

输出

For each test case, print a single integer — the number of different [a,b,c,d] tuples.

思路:
PS:好久没写了感觉有点生疏了。
题目的大致意思是给定一个有n个不同的数构成的数组P,1<=Pi<=n,求满足Pa<Pc,Pb>Pd且a<b<c<d的四元组有多少。当时思路是先确定a和c的位置,然后计算b与d的对数。a与c确定后,对于一个b来说能与它配对的d的个数为大于c中Pd<Pb的个数。为了加快计算速度,可以用树状数组分别去维护c+1至n存在的数与a+1至c-1存在的数。以先第一重循环枚举a第二重循环枚举c为例,枚举c后(b,d)的对数为{c-1时的对数}减去{a+1至c-2中大于Pc的数}加上{c+1至n中小于Pc-1的数},若此时满足Pa<Pc则加上此时满足条件(b,d)的对数。
dp[a][c] = dp[a][c-1] + cnt(c+1,n,P[c-1]) - ( cnt(a+1,c-2,n) - cnt(a+1,c-2,P[c]) )
dp[a][c]为a与c确定后符合条件的(b,d)对数
a+1<c,dp[a][a+1]=0;
cnt(l,r,x)为求数组[l,r]中小于等于x的个数。

#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
const int Ms=5005;
int T[2][Ms];
int a[Ms];
int lowbit(int  x)
{
    return x&(-x);
}
void update(int no,int key,int x)
{
    while(key<=Ms)
    {
        T[no][key]+=x;
        key+=lowbit(key);
    }
}
int getsum(int no,int key)
{
    int sum=0;
    while(key>0)
    {
        sum+=T[no][key];
        key-=lowbit(key);
    }
    return sum;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        long long ans=0,tmp=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(int i=1;i<=n-3;i++)
        {
            memset(T,0,sizeof T);
            for(int p=i+3;p<=n;p++)update(1,a[p],1);
            tmp=0;
            for(int j=i+2;j+1<=n;j++)
            {
                update(0,a[j-1],1);
                tmp+=getsum(1,a[j-1]);
                if(a[i]<a[j])
                {
                    ans+=tmp;
                }
                tmp-=getsum(0,n)-getsum(0,a[j+1]);
                update(1,a[j+1],-1);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

若有什么错误,欢迎指正^ _ ^ 。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值