题目链接

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. beta-1 阶段各组员的贡献分分配

    小组名称:飞天小女警 项目名称:礼物挑选小工具 小组成员:沈柏杉(组长).程媛媛.杨钰宁.谭力铭 bera-1阶段各组员的贡献分分配如下: 姓名 团队贡献分 谭力铭 5.2 沈柏杉 5.1 程媛媛 4 ...

  2. [转帖]Linux 的UTC 和 GMT

    1.问题 对于装有Windows和Linux系统的机器,进入Windows显示的时间和Linux不一致,Linux中的时间比Windows提前8个小时. 2.解决方法 修改/etc/default/r ...

  3. mysql & vs2013

    一 mysql 版本介绍 在mysql的官网http://dev.mysql.com/上,mysql 大致分为两个版本,即免费的社区版(community)和 付费的商业版(commercial).其 ...

  4. Android Studio -导入项目 gradle处理

    如果导入 android studio 项目, 那么一定要注意 需要合适的gradle版本,具体方法为: 首先导入步骤: 打开android studio ==> File ==> New ...

  5. TDDL调研笔记

    一,TDDL是什么 Taobao Distributed Data Layer,即淘宝分布式数据层,简称TDDL .它是一套分布式数据访问引擎 淘宝一个基于客户端的数据库中间件产品 基于JDBC规范, ...

  6. SWERC2015-I Text Processor

    题意 给一个长度为\(n\)的字符串\(s\),再给定一个\(w\),问对于所有的\(i\in [1,n-w+1]\),\(s[i..i+w-1]\)有多少个不同字串.\(n,w\le 10^5\). ...

  7. bug:margin合并

    demo1和demo2存在margin合并问题:外边距合并指的是,当两个垂直外边距相遇时,它们将形成一个外边距.合并后的外边距的高度等于两个发生合并的外边距的高度中的较大者.弥补方案:bfc; 添加一 ...

  8. IBatis Map报错10.1

    检查 providers.config 把没用的给关闭掉即可

  9. day29:关闭服务|

    1. 在centos6系统里,我们可以使用ntsysv关闭不需要开机启动的服务,当然也可以使用chkconfig工具来实现. 写一个shell脚本,用chkconfig工具把不常用的服务关闭.脚本需要 ...

  10. Android ActionBar 使用详解

    ActionBar取代了以前的TitleBar,是一种更加灵活的人机交互方式:ActionBar并不是完全自立门户的一个新兴的东西,而是和3.0以下版本的menu进行了合并整合:so,添加action ...