HDU 6058

Posted 温和的提比略

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 6058相关的知识,希望对你有一定的参考价值。

题意略。

思路:这题要求第k大之和,我们可以算每个数字对答案的贡献。这次,我们采取一个特殊的手法:我们按数字的大小,从小到大来计算贡献。

先从1开始计算,我们知道,1周围的数字都比1大,假设1在位置p,那么它能做出贡献的区间是:[p - k + 1,p],[p - k + 2,p + 1],...,[p,p + k -1]。

如果每一个数字都能像1这样就好了,从而我们想到用一个双向链表来维护这个体系,每计算完一个数字我们就把这个数字从我们的链表中删去,

这样就可以总是保证当前计算的那个数字周围的数都比它大(有点像离线的思想)。

 

详见代码:

#include<bits/stdc++.h>
typedef long long LL;
const LL maxn = 5 * 1e5 + 5;

int lft[maxn],rht[maxn],mp[maxn];
int store1[100],store2[100],s,t;
int n,k;

void dlt(int pos){
    int l = lft[pos],r = rht[pos];
    rht[l] = r,lft[r] = l;
}

int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&k);
        int temp;
        for(int i = 1;i <= n;++i){
            lft[i] = i - 1,rht[i] = i + 1;
            scanf("%d",&temp);
            mp[temp] = i;
        }
        LL ans = 0;
        for(int i = 1;i <= n;++i){
            memset(store1,-1,sizeof(store1));
            memset(store2,-1,sizeof(store2));
            s = 0,t = 0;
            int pos = mp[i];
            for(int j = 0,ptr = pos;j < k + 1 && ptr;ptr = lft[ptr],++j)
                store1[++s] = ptr;
            for(int j = 0,ptr = pos;j < k + 1 && ptr != n + 1;ptr = rht[ptr],++j)
                store2[++t] = ptr;
            for(int j = s;j >= 1;--j){
                LL L,R;
                int l1 = store1[j],l2 = store1[j + 1];
                L = (l2 == -1 ? l1 : l1 - l2);
                int r1 = store2[k - j + 1],r2 = store2[k - j + 1 + 1];
                if(r1 == -1) R = 0;
                else R = (r2 == -1 ? n - r1 + 1 : r2 - r1);
                ans += L * R * i;
            }
            dlt(pos);
        }
        printf("%lld\n",ans);
    }
    return 0;
} 

 

以上是关于HDU 6058的主要内容,如果未能解决你的问题,请参考以下文章

hdu 6058

HDU 6058 Kanade's sum(链表)

HDU 6058

hdu-6058 Kanade's sum

链表2017多校训练3 HDU 6058 Kanade's sum

HDU 6058 Kanade's sum —— 2017 Multi-University Training 3