2017 Multi-University Training Contest - Team 3 & hdu6058、Kanade's sum

题目:

Problem Description
Give you an array A[1..n] of length n .

Let f(l,r,k) be the k-th largest element of A[l..r] .

Specially , f(l,r,k)=0 if rl+1<k .

Give you k , you need to calculate nl=1nr=lf(l,r,k)

There are T test cases.

1T10

kmin(n,80)

A[1..n] is a permutation of [1..n]

n5105
 

Input
There is only one integer T on first line.

For each test case,there are only two integers n , k on first line,and the second line consists of n integers which means the array A[1..n]
 

Output
For each test case,output an integer, which means the answer.
 

Sample Input
  
  
1 5 2 1 2 3 4 5
 

Sample Output
  
  
30
题意:求给定数组的所有子区间中第K大值的和。

思路:考虑当前以元素a[i]为第k大值的区间数(sum),向右查找比a[i]大的k-1个值(用数组b[cnt]记录比a[i]大的值的位置,b[1]=i;)。

(一)、若找到第k-1个值,num=1(目前为止,区间数为1个),接着向右找比a[i]小的值的个数num(再次遇见比a[i]大的值就结束查找)。num为以a[i]为第k大值的区间个数,sum+=num。然后向左查找,若当前值比a[i]小,找到一个就sum+=num,多出num个区间;若当前值比a[i]大,且cnt!=1,更新区间数num为b[cnt]-b[cnt-1],cnt--,sum+=num。

(二)、向右没找到k-1个比a[i]大的值,就继续从i-1开始向左找。找到k-1个比a[i]大的值后,对b数组排序。num=n-b[cnt]+1,sum+=num;继续向左找,若比a[i]小,sum+=num;若比a[i]大,且b[cnt]!=i,就更新num的值为b[cnt]-b[cnt-1],同(一)中步骤。

具体看代码,模拟题,麻烦,运行时间也是接近临近值~

CODE:

#include<bits/stdc++.h>
using namespace std;
int a[1000005],b[1000005];
int main()
{
        int t,n,i,j,k;
        scanf("%d",&t);
        while(t--){
                scanf("%d%d",&n,&k);
                for(i=1;i<=n;i++) scanf("%d",&a[i]);
                __int64 ans=0;
                for(i=1;i<=n;i++){
                        int x=a[i],cnt=0,sum=0;
                        b[++cnt]=i;
                        for(j=i+1;j<=n&&cnt<k;j++) if(a[j]>x) b[++cnt]=j;
                        if(cnt==k){
                                int num=1;
                                for(;j<=n;j++) if(a[j]<x) num++;else break;
                                sum+=num;
                                for(j=i-1;j>0&&cnt>0;j--){
                                        if(a[j]<x) sum+=num;
                                        else{
                                                if(cnt==1) break;
                                                num=b[cnt]-b[cnt-1];
                                                cnt--;
                                                sum+=num;
                                        }
                                }
                        }
                        else{
                                for(j=i-1;j>0&&cnt<k;j--) if(a[j]>x) b[++cnt]=j;
                                if(cnt==k){
                                        sort(b,b+cnt+1);
                                        int num=n-b[cnt]+1;
                                        sum+=num;
                                        for(;j>0&&b[cnt]>=i;j--){
                                                if(a[j]<x) sum+=num;
                                                else{
                                                        if(b[cnt]==i) break;
                                                        num=b[cnt]-b[cnt-1];
                                                        cnt--;
                                                        sum+=num;
                                                }
                                        }
                                }
                        }
                        ans+=(__int64)sum*x;
                }
                printf("%I64d\n",ans);
        }
        return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值