zoukankan      html  css  js  c++  java
  • hdu 6058---Kanade's sum(链表)

    题目链接

    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
     
     
    题意:输入n,k  然后输入n个数(1~n的排列),求所有子区间的第k大数之和(长度小于k的区间值为0)。
     
    思路:考虑每个数的贡献值,对于每个数求有多少个区间的第k大数是它,所以我们需要求出每个数向左比它大的k个数的位置,向右比它大的k个数的位置,根据这些位置就可以算出有多少区间它是第k大(这个就不详细说了),那么怎么求向左向右比它大的k数的位置呢,直接求复杂度比较高,我们可以按照1~n的数值大小顺序求向左向右的比它大的k个数的位置,用链表维护,算完i之后,将i从链表里面删除,那么剩余的都是比i+1大的数了,所以直接向左右遍历k个数即可。
     
    代码如下:
    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef long long LL;
    const int N=5e5+5;
    struct Node
    {
        int x;
        int l,r;
    }t[N];
    int a[N], L[85], R[85];
    
    int main()
    {
        int T,n,k;  cin>>T;
        while(T--)
        {
            scanf("%d%d",&n,&k);
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&t[i].x);
                t[i].l=i-1; t[i].r=i+1;
                a[t[i].x]=i;
            }
            t[1].l=-1; t[n].r=-1;
    
            LL ans=0;
            for(int i=1;i<=n;i++)
            {
                //ans=0;
                int pos=a[i];
                int tot=0;///
                for(int j=t[pos].r;j!=-1;j=t[j].r)
                {
                    R[++tot]=j;
                    if(tot>=k) break;
                }
                R[0]=tot;
                if(tot<k)  R[tot+1]=n+1;
    
                tot=0;    ///
                for(int j=t[pos].l;j!=-1;j=t[j].l)
                {
                    L[++tot]=j;
                    if(tot>=k) break;
                }
                L[0]=tot;
                if(tot<k)  L[tot+1]=0;
    
                int l=t[pos].l;
                int r=t[pos].r;
                if(l>0) t[l].r=r;
                if(r>0) t[r].l=l;
    
                for(int j=L[0]; j>=0; j--)
               {
                   if(j>=k) continue;
                   int x=k-1-j;
                   if(x>R[0]) continue;
                   int l=L[j]-L[j+1];
                   if(j==0) l=pos-L[1];
                   int r=R[x+1]-R[x];
                   if(x==0) r=R[1]-pos;
                   ans+=(LL)l*(LL)r*(LL)t[pos].x;
               }
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    虚树入门
    378. 骑士放置(最大独立集)
    377. 泥泞的区域(最大点集)
    352. 闇の連鎖
    P2680 运输计划
    Linux下的段错误(Segmentation fault)
    Acwing 98-分形之城
    快速幂 和 快速乘
    P1308-道路修建 (noi 2011)
    洛谷 P1070 道路游戏(noip 2009 普及组 第四题)
  • 原文地址:https://www.cnblogs.com/chen9510/p/7289493.html
Copyright © 2011-2022 走看看