题目链接

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. PSP 进度条 柱状图 饼状图

    9号 类别 开始时间 结束时间 间隔 净时间 燃尽图 8::00 8:20 0 20分钟 站立会议 8:20 8:50 0 30分钟 读构建之法 9:20 13:20 120分钟 120分钟 四人小组 ...

  2. oracle & 的用法!

    /*select * from emp_bak where deptno = &"Department number" order by ename; select * f ...

  3. Mysql中关键词执行顺序

    MySQL的语句执行顺序 MySQL的语句一共分为11步,最先执行的总是FROM操作,最后执行的是LIMIT操作.其中每一个操作都会产生一张虚拟的表,这个虚拟的表作为一个处理的输入,只是这些虚拟的表对 ...

  4. post和updatebatch区别 delphi

    Post是确认当前的修改,而UpdateBatch是把已经确认但是没有存盘的数据写入数据库如果不是使用批量更新的方式的时候,Post的时候,确认的修改直接写入数据库. 我弄了一个例子是ado的.往数据 ...

  5. postman优缺点

    postman优缺点分析 优点:门槛低,上手快 优点: 脚本语言是js 优点:自带各种代码模块 优点:跨平台 优点: 免费版就已经非常强大了,支持http,https协议 优点:有命令行版本,newm ...

  6. 第167天:canvas绘制柱状图

    canvas绘制柱状图 1.HTML <!DOCTYPE html> <html lang="en"> <head> <meta char ...

  7. BZOJ 1177 Oil(特技枚举)

    对于三个正方形的位置一共有六种情况. 预处理出(i,j)左上角,左下角,右上角,右下角区域内最大权值的正方形. 枚举分界线更新答案. 刚开始想了一个错误的DP也是蠢啊. #include<set ...

  8. 在洛谷3369 Treap模板题 中发现的Splay详解

    本题的Splay写法(无指针Splay超详细) 前言 首先来讲...终于调出来了55555...调了整整3天..... 看到大部分大佬都是用指针来实现的Splay.小的只是按照Splay的核心思想和原 ...

  9. CF449,急需提高姿势水平

    这可能是我第1场只出1题的div1? A 鬼畜题? 我的dev没有字符统计功能,于是只好扔到notepad++上.数错好几次.题目本身没什么特别的地方. B 当时一直没想出来QAQ 题目中说m> ...

  10. Netsh命令-网络禁用开启

    禁用无线网卡:netsh interface set interface wlan0 disabled 启用无线网卡:netsh interface set interface wlan0 enabl ...