题目链接

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 r−l+1<k.

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

There are T test cases.

1≤T≤10

k≤min(n,80)

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

∑n≤5∗105

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

题意:

给你一个n个数的排列,问你全部区间第k大的总和为多少。

分析:

我们只要求出对于一个数x左边最近的k个比他大的和右边最近k个比他大的,扫一下就可以知道有几个区间的k大值是x。

我们考虑从小到大枚举x,每次维护一个链表,链表里只有>=x的数,那么往左往右找只要暴力跳k次,删除也是O(1)的。

时间复杂度:O(nk)

这题只要是知道能从小到大枚举就好办了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; const int N=5e5+7;
int t,n,k,a[N],idx[N];///a表示的是这个数组,idx表示的是某个数在的位置
struct Node
{
int pre,nxt,idx;
} node[N]; int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]),idx[a[i]]=i;
node[i]=Node {i-1,i+1,i};
}
node[n+1].idx=n+1;
ll ans=0;
for(int i=1;i<=n;i++)///找到当前这个数
{
int l=idx[i],r=idx[i];///左端点,右端点
int cntl=1,cntr=0;///往前、往后找的数的个数
while(cntl<k)///往前找,看有这个数的前面有多少个数
{
if(node[l].pre==0)break;///左端点已经是第一个元素了
cntl++,l=node[l].pre;
}
while(cntl)///在前面有这么多数的基础上
{
while(cntr+cntl>k)///左右区间的个数大于k了
{
cntr--,r=node[r].pre;///右区间往前移动
}
while(cntl+cntr<k)///左右区间的个数小于k了
{
if(node[r].nxt==n+1)break;///移动到最后也就结束了,不能再往后移动
cntr++,r=node[r].nxt;///右区间往后移动
}
if(cntl+cntr==k)///正好左右区间中有这么多数
{
int L=node[l].idx-node[node[l].pre].idx;///左边涉及的区间
int R=node[node[r].nxt].idx-node[r].idx;///右边涉及的区间
ans+=1ll*L*R*i;
printf("L====%d R====%d i===%d\n",L,R,i);
}
l=node[l].nxt,cntl--;///左区间往后移动
}
node[node[idx[i]].pre].nxt=node[idx[i]].nxt;
node[node[idx[i]].nxt].pre=node[idx[i]].pre;
}
printf("%lld\n",ans);
}
return 0;
}

还有一种纯模拟的方法,比赛的时候我们就是尝试用模拟在写,但是中间的寻找过程没有处理好,时间总是会超,纯模拟的时间控制在O(n^2).下面讲一下具体的解题思路把。

1.我们将当前的a[i]值看作是我们要找的一个区间内的第k大数,获得这个数咋整个数组中的下标。

2.从这个数开始往后找,我们只需要关注比当前这个数大的元素,用一个数组将这些元素保存下来(保存的不是这些数本身,而是它们于我们的第k大值a[i]之间的元素差,即用这个数的小标j减去i)直到找到数组末尾或者说找到了k-1个比a[i]大的数则结束。

3.如果说我们在第二步中找到了k-1个比a[i]大的数,即我们的j在上一步走到了n的位置,那么我们可以虚拟一下第n+1位有一个比a[i]大的元素,也将它加入到第二步里面的数组后面。

4.我们开始从坐标i-1往前找,找的也是比a[i]大的元素,依旧将这些元素与i的下标差保存下来,直到找到最前面或者说找到了k-1个数。这里同第三步一样,如果找到了最前面也就意味着没有找到k-1个元素,虚拟数组0位之间还有一个比a[i] 大的元素,将其保存下来。

5.然后遍历左边的区间,每一次相当于左边能加上一个,右边的区间能减去一个,且保证这之间的元素的个数正好为k个,那么左边区间当前取到的最前面的元素与再前面那个元素之间的元素个数,加上右面区间最后面的那个元素与其后面那个元素的元素个数就是整个区间可以变化的次数。乘上当前的a[i]。

注意,这里说所的最前面的元素是指对于,取得的这k个元素的区间来说的。

#include<iostream>
#include<cstdio>
using namespace std;
#define read(a) scanf("%d",&a)
#define LL long long
const int maxn=500000+10;
int a[maxn];
int l[maxn],r[maxn];
int main()
{
int t;
read(t);
while(t--)
{
int n,k;
read(n);
read(k);
for(int i=0;i<n;i++)
{
read(a[i]);
}
LL ans=0;
for(int i=0;i<n;i++)
{
int lcnt=1,rcnt=1,j;///lcnt代表元素a[i]左边比他大的数有多少个,rcnt同理
for( j=i+1;j<n;j++)
{
if(rcnt>k)
break;
if(a[j]>a[i])
{
r[rcnt++]=j-i;///r[rcnt]代表右边第rcnt个比a[i]大的数距离a[i]的距离,这个是方便计算的,可以等于j,
///但是计算的时候要特殊处理右边只有一个比a[i]大的时候,下方的rnum=1,比较麻烦,
///原来是那样做的,不建议
}
}
if(j>=n)
r[rcnt]=n-i; ///如果a[i]右边比他大的数没超过k个,
///那么我们知道a[i]右边比他大的数只有rcnt-1个,
///我们假设距离a[i]最远的比他大的那个数为righht,
///(程序中没有right这个变量,这里就是为了方便理解)
///这里的r[rcnt]就是为了方便后面统计right右边有多少个比a[i]小的数
for(j=i-1;j>=0;j--)
{
if(lcnt>k)
break;
if(a[j]>a[i])
{
l[lcnt++]=i-j;///同理上面
}
}
if(j<=0)
l[lcnt]=i+1;///同理上面
for(j=0;j<lcnt;j++)
{
if(k-j-1>=rcnt)
continue;
int lnum=l[j+1]-l[j];
int rnum=r[k-j]-r[k-j-1];
ans+=(LL)a[i]*lnum*rnum;
}
}
printf("%lld\n",ans);
}
return 0;
}

2017ACM暑期多校联合训练 - Team 3 1003 HDU 6058 Kanade's sum (模拟)的更多相关文章

  1. 2017ACM暑期多校联合训练 - Team 8 1008 HDU 6140 Hybrid Crystals (模拟)

    题目链接 Problem Description Kyber crystals, also called the living crystal or simply the kyber, and kno ...

  2. 2017ACM暑期多校联合训练 - Team 7 1009 HDU 6128 Inverse of sum (数学计算)

    题目链接 Problem Description There are n nonnegative integers a1-n which are less than p. HazelFan wants ...

  3. 2017ACM暑期多校联合训练 - Team 6 1003 HDU 6098 Inversion (模拟)

    题目链接 Problem Description Give an array A, the index starts from 1. Now we want to know Bi=maxi∤jAj , ...

  4. 2017ACM暑期多校联合训练 - Team 4 1003 HDU 6069 Counting Divisors (区间素数筛选+因子数)

    题目链接 Problem Description In mathematics, the function d(n) denotes the number of divisors of positiv ...

  5. 2017ACM暑期多校联合训练 - Team 1 1003 HDU 6035 Colorful Tree (dfs)

    题目链接 Problem Description There is a tree with n nodes, each of which has a type of color represented ...

  6. 2017ACM暑期多校联合训练 - Team 2 1003 HDU 6047 Maximum Sequence (线段树)

    题目链接 Problem Description Steph is extremely obsessed with "sequence problems" that are usu ...

  7. 2017ACM暑期多校联合训练 - Team 4 1004 HDU 6070 Dirt Ratio (线段树)

    题目链接 Problem Description In ACM/ICPC contest, the ''Dirt Ratio'' of a team is calculated in the foll ...

  8. 2017ACM暑期多校联合训练 - Team 9 1005 HDU 6165 FFF at Valentine (dfs)

    题目链接 Problem Description At Valentine's eve, Shylock and Lucar were enjoying their time as any other ...

  9. 2017ACM暑期多校联合训练 - Team 9 1010 HDU 6170 Two strings (dp)

    题目链接 Problem Description Giving two strings and you should judge if they are matched. The first stri ...

随机推荐

  1. tomcat下部署了多个项目启动报错java web error:Choose unique values for the 'webAppRootKey' context-param in your web.xml files

    应该是tomcat下部署了多个项目且都使用log4j. <!--如果不定义webAppRootKey参数,那么webAppRootKey就是缺省的"webapp.root". ...

  2. FastReport.Net 无限页高(连续纸小票)

    using System; using System.Collections; using System.Collections.Generic; using System.ComponentMode ...

  3. struct和class的联系与区别

    C++支持另一个关键字struct,它也可以定义类类型.struct关键字是从C语言继承过来的. 默认初始访问级别不同: 如果使用class关键字来定义类,那么定义在第一个访问标号前的任何成员都隐式指 ...

  4. a标签不能嵌套

    <a href='http://www.baidu.com'> <a href='http://www.google.com'></a> </a> &l ...

  5. 第156天:canvas(三)

    一.变形 1.1 translate translate(x, y) ​ 用来移动 canvas 的原点到指定的位置 ​ translate方法接受两个参数.x 是左右偏移量,y 是上下偏移量,如右图 ...

  6. Spring Cloud Config

    1.config服务端配置 1.1 引入依赖 <dependency> <groupId>org.springframework.boot</groupId> &l ...

  7. 【bzoj2257】[Jsoi2009]瓶子和燃料 扩展裴蜀定理+STL-map

    题目描述 给出 $n$ 个瓶子和无限的水,每个瓶子有一定的容量.每次你可以将一个瓶子装满水,或将A瓶子内的水倒入B瓶子中直到A倒空或B倒满.从中选出 $k$ 个瓶子,使得能够通过这 $k$ 个瓶子凑出 ...

  8. 【bzoj5146】有趣的概率 微积分

    题目描述 "可爱的妹子就像有理数一样多,但是我们知道的,你在数轴上随便取一个点取到有理数的概率总是0,"芽衣在床上自顾自的说着这句充满哲理的话,"诶,柚子,我写完概率论的 ...

  9. 【Java】Java CSV操作代码

    CSV是逗号分隔文件(Comma Separated Values)的首字母英文缩写,是一种用来存储数据的纯文本格式,通常用于电子表格或数据库软件.在 CSV文件中,数据“栏”以逗号分隔,可允许程序通 ...

  10. 【转】大数据分析(Big Data OLAP)引擎Dremel, Tenzing 以及Impala

    引自:http://blog.csdn.net/xhanfriend/article/details/8434896 对于数据分析师来说,SQL是主要的语言. Hive为Hadoop提供了支持SQL运 ...