2017 Multi-University Training Contest

来源:互联网 发布:数据库分组查询原理 编辑:程序博客网 时间:2024/06/06 01:18
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
15 21 2 3 4 5
Sample Output
30


题目大意:给你一个长度为n的数列(里面的数为1~n全部都包括顺序未知)给你一个数k。求【r,l】区间内的第k大的数的总和为多少。

解题思路:正着去求不好求还容易超时,用x遍历1~n  那么就想着求有哪些区间内的第k大的数为x把区间的个数求出来然后乘以x最后所有的相加就是最后的答案。

先求x左边第k个比x大的数再求x的右边第k个比x大的数,然后先以x为区间的右边界这时x右边的可用的点为x与它右边第一个比他大的数左边可用的点就为它第k个比它大的数与第k-1个比它大的数之间的个数令他们相乘然后向右移每次都进行这样的操作最后就能求出答案。

#include<cstring>#include<cstdio>#include<string>#include<iostream>#define N 500005using namespace std;typedef long long LL;int num[N];int a[85],b[85];LL sum;int main(){    int t,i,j,n,cnta,cntb,k;    scanf("%d",&t);    while(t--)    {        sum=0;        scanf("%d%d",&n,&k);        for(i=0; i<n; i++)        {            scanf("%d",&num[i]);        }        for(i=0; i<n; i++)        {            cnta=cntb=1;            int tp=num[i];            a[0]=b[0]=0;            for(j=i-1; j>=0; j--)            {                if(cnta>k)                {                    break;                }                if(num[j]>tp)                {                    a[cnta++]=i-j;                }            }            if(j<=0)            {                a[cnta]=i+1;            }            for(j=i+1; j<n; j++)            {                if(cntb>k)                {                    break;                }                if(num[j]>tp)                {                    b[cntb++]=j-i;                }            }            if(j>=n)            {                b[cntb]=n-i;            }            /*for(int l=0; l<=cnta; l++)            {                printf("%d\n",a[l]);            }            for(int f=0; f<=cntb; f++)            {                printf("%d\n",b[f]);            }*/            for(int ii=0; ii<cnta; ii++)            {                if(k-ii-1>=cntb)                {                    continue;                }                int tp1=a[ii+1]-a[ii];                int tp2=b[k-ii]-b[k-ii-1];                sum+=(LL)num[i]*tp1*tp2;            }        }        printf("%lld\n",sum);    }    return 0;}

(本博客借鉴http://blog.csdn.net/fanbaobao829/article/details/76548912?locationNum=2&fps=1)

另一种写法是用的链表,比较快

思路:
1,寻找某个数位置在其前面的k个比它大的数以及k个位置在其后面的比他大的数。
2,题意可以转化为求某个数在多少个区间中是第k大的数,然后将结果加起来。
3,从小到大枚举可能成为第k大的数,由于是从小到大的枚举,那么剩下的数一定都是大于等于他的,这样也就省去了大小的比较。枚举之后维护链表将其删除。

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn=500009;int T,n,k,a[maxn],pos[maxn],pre[maxn],np[maxn];int s[maxn],t[maxn];long long ans=0;int main(){    scanf("%d",&T);    while(T--)    {        scanf("%d%d",&n,&k);        for(int i=1;i<=n;i++)        {            scanf("%d",&a[i]);            pos[a[i]]=i;//记录位置            pre[i]=i-1;//链表前驱            np[i]=i+1;//链表后继        }        ans=0;        int s0=0,t0=0;        for(int num=1;num<=n-k+1;num++)//枚举可能成为第k大的数        {            int p=pos[num];            s0=0,t0=0;            //寻找前后k个比它大的数            for(int i=p;i&&s0<=k+1;i=pre[i])                s[++s0]=i;            for(int j=p;j<=n&&t0<=k+1;j=np[j])                t[++t0]=j;            //首尾额外添加两个无限大的数            s[++s0]=0;            t[++t0]=n+1;            for(int i=1;i<=s0-1;i++)            {                int tmp=k-i+1;                if(tmp<=t0-1&&tmp>0)                    ans+=(s[i]-s[i+1])*1LL*(t[tmp+1]-t[tmp])*num;            }            //从链表中将此数删除            int tpre=pre[p];            int tnp=np[p];            if(tpre) np[tpre]=tnp;            if(tnp<=n) pre[tnp]=tpre;            pre[p]=np[p]=0;        }        printf("%I64d\n",ans);    }    return 0;}



原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 京东买的kindle坏了怎么办 欧巴怎么办韩语怎么写 聚划算淘宝口令打不开怎么办 道聚城白银礼包下架怎么办 聚星输了很多钱怎么办 弹力运动裤被烟烧了个洞怎么办 生完宝宝胯宽怎么办 黑色纯棉裤子洗的发白怎么办 金盾保险柜密码忘了怎么办 装修好的房子漏水怎么办 刚装修的房子墙面开裂怎么办 刚装修的房子有味道怎么办 代销产品规格填写不完整怎么办 我的信息被泄露怎么办 进入不良网站手机发信息怎么办 发不良信息被停机了怎么办 手机qq登录显示被冻结怎么办 qq账户被冻结了怎么办 qq钱包账户被永久冻结怎么办 怎么办转让费还没给我 收钱吗不能抵用红包怎么办 红包抵扣被关了怎么办 天猫客户给差评怎么办 淘宝闪电退款有纠纷怎么办呀 手机屏幕右下角出现彩色点怎么办 在超市买到假货怎么办 天猫超市多发货怎么办 天猫中不小心取消退款了怎么办 天猫超市写错了怎么办 二维码收付款不到红包怎么办 天猫优惠劵过期了怎么办 天猫购物津贴用不完怎么办 天猫上买的大件东西实物不符怎么办 天猫上面料成分与实物不符怎么办 闲鱼发货与实物不符怎么办 天猫超市买贵了怎么办 天猫超市里购买的东西退货怎么办 淘宝店上传的图片不清楚怎么办 微信图片打印出来不清楚怎么办 微信图片打印不清楚怎么办 淘宝上传商品视频不清楚怎么办