hdu 6058 Kanade's sum(模拟链表)

Kanade's sum

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2723    Accepted Submission(s): 1132

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

 

Source
 
Recommend
liuyiding   |   We have carefully selected several similar problems for you:  6119 6118 6117 6116 6115 
 

题目大意:给出一个n和一个k,求1~n的每个区间的第k大的总和是多少,区间长度小于k的话,贡献为0.

题解:一开始先维护一个满的链表,然后从小到大删除,每次算完一个数,就在链表里面删除,算x的时候,保证删除的数都比x小,都可以用来算贡献。i和pre[i]和nxt[i]的距离就是小于当前的数的数目+1。

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
int T,n,k;
long long ans;
int pos[1000005],a[1000005];
int pre[1000005],nxt[1000005];
long long lnum[1000],rnum[1000];


void del(int p)
{
    pre[nxt[p]]=pre[p];
    nxt[pre[p]]=nxt[p];
}

int main()
{
     scanf("%d",&T);
    for(;T>0;T--)
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            pos[a[i]]=i;
        }

        for(int i=1;i<=n;i++)
        {
            pre[i]=i-1;
            nxt[i]=i+1;
        }
        ans=0;

        for(int i=1;i<=n-k+1;i++) //枚举第 k 大的数是 i 时
        {
           int l=0,r=0;

           for(int j=pos[i];j>0 && l<=k;j=pre[j])  // 在i这个数位置的左边,比i大的k个数的位置
              lnum[++l]=j-pre[j];


           for(int j=pos[i];j<=n && r<=k;j=nxt[j]) // 在i这个数位置的右边,比i大的k个数的位置
              rnum[++r]=nxt[j]-j;

           for(int j=1;j<=l;j++)
            if (k-j+1<=r && k-j+1>=1)  // 求的是一个区间内,已经满足i为第k大的情况下,能微调的位置种数(lnum[j]-lnum[j+1])*(rnum[k-j+2]-rnum[k-j+1])
               ans=ans+lnum[j]*rnum[k-j+1]*i;

           del(pos[i]); //删除

        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

posted on 2017-08-14 14:17  Yxter  阅读(141)  评论(0编辑  收藏  举报

导航