hdu-6058 Kanade's sum

  题意:略

  思路:要我们求每个区间第K大数之和,其实可以转换为求多少个区间的第K大数是X,然后我们在求和就好了。

     那么我们可以从小到大枚举所有可能成为第K大的数。为什么从小到大呢?

     因为从小到大我们就略去了大小的比较了,后面我们维护的链表就要把这个值除去。

/*  gyt
       Live up to every day            */
#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
#include<cstring>
#include<queue>
#include<set>
#include<string>
#include<map>
#include <time.h>
#define PI acos(-1)
using namespace std;
typedef long long ll;
typedef double db;
const int maxn = 510000+10;
const ll maxm = 1e7;
const int modd = 10000007;
const int INF = 1<<30;
const db eps = 1e-9;
int pos[maxn], pre[maxn], nex[maxn];

void solve() {
    int n, k;  scanf("%d%d", &n, &k);
    for (int i=1; i<=n; i++) {
        int x;  scanf("%d", &x);
        pos[x]=i;  pre[i]=i-1,  nex[i]=i+1;
    }
    pre[0]=0;  nex[n+1]=n+1;
    ll sum=0;
    for (int j=1; j<=n; j++) {
        int x=pos[j];
        int rq[110];
        int lc=0, rc=0;
       // cout<<"x:"<<x<<endl;
        for (int i=x; i<=n&&rc<k; i=nex[i]) {
            rq[++rc]=nex[i]-i;
           // cout<<nex[i]<<" "<<i<<endl;
        }
        ll ans=0;
        for (int i=x; i>0&&lc<k; i=pre[i]) {
            lc++;
            int r=k-lc+1;
            if (r>rc)  continue;
            ans+=(i-pre[i])*rq[r];  //前面有多少个比他小的数,我们就可以构成那么多的区间
            //cout<<"ans:"<<ans<<endl;
            //cout<<(i-pre[i])<<" "<<rq[r]<<endl;
        }
        //cout<<"rc:"<<rc<<" lc:"<<lc<<endl;
        sum+=ans*j;
        pre[nex[x]]=pre[x];
        nex[pre[x]]=nex[x];
        //cout<<j<<" "<<ans<<endl;
        //cout<<"---------------"<<endl;
    }
    cout<<sum<<endl;
}
int main() {
    int t = 1;
    //freopen("in.txt", "r", stdin);
    scanf("%d", &t);
    //getchar();
    while(t--)
        solve();
    return 0;
}

hdu-6058 Kanade's sum

时间: 2024-09-30 19:05:06

hdu-6058 Kanade's sum的相关文章

hdu 6058 Kanade&#39;s sum(链表)

题目链接:hdu 6058 Kanade's sum 题意: 给你一个n个数的排列,问你全部区间第k大的总和为多少. 题解: 我们只要求出对于一个数x左边最近的k个比他大的和右边最近k个比他大的,扫一下就可以知道有几个区间的k大值是x. 我们考虑从小到大枚举xxx,每次维护一个链表,链表里只有>=x的数,那么往左往右找只要暴力跳kkk次,删除也是O(1)的. 时间复杂度:O(nk) 这题只要是知道能从小到大枚举就好办了. 1 #include<bits/stdc++.h> 2 #defi

HDU 6058 Kanade&#39;s sum —— 2017 Multi-University Training 3

Kanade's sum Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2512    Accepted Submission(s): 1045 Problem Description Give you an array A[1..n]of length n. Let f(l,r,k) be the k-th largest eleme

HDU 6058 Kanade&#39;s sum(链表)

http://acm.hdu.edu.cn/showproblem.php?pid=6058 题意:找出所有区间第K大的值之和. 思路: 又有点贡献值的味道,就是考虑当前这个数贡献了几个区间. 然后往左和往右分别找大于当前数的k-1个数,这样就可以确定区间的个数,这要求我们从小到大找 并且找完之后需要删除这个数,用链表来维护. 删除元素的目的是为了加速,保证了当前查找的元素是最小值,所以只需要跳跃寻找k次就可以.具体看代码. 1 #include<iostream> 2 #include<

【链表】2017多校训练3 HDU 6058 Kanade&#39;s sum

acm.hdu.edu.cn/showproblem.php?pid=6058 [题意] 给定一个排列,计算 [思路] 计算排列A中每个数的贡献,即对于每个ai,计算有ni个区间满足ai是区间中的第k大,那么ai对答案的贡献就是ai*ni 以ai为起点,统计ai右边离ai最近的,比ai大的k个数的位置 同理统计左边的位置,组合得到答案 关键是得到比ai大的离ai最近的k个数的位置 因为是排列,所以每个数都不相等,可以记录每个数的位置,然后从小到大枚举ai,这样维护一个双向链表,保证链表中的数就是

6058 Kanade&#39;s sum 链表维护()

题意:给出元素为[1,n]的排列a,定义f[l,r,k]为区间[l,r]内第k大的元素.给出k,求 累加和(l=1~n,r~l~n)f[l,r,k] . n<=5e5,k<=min(80,n)k<=80 a[i]贡献: 枚举左边有p个比它大,右边要有k-1-p个比它大.如何处理出左/右边第p个比它大的位置?从最小的数开始处理,链表初始满链,维护一个链表,当处理x时,链表中只有比x大的数 #include <bits/stdc++.h> using namespace std;

【set】【链表】hdu6058 Kanade&#39;s sum

f(l,r,K)表示区间l,r里面的K大值,问你所有连续子区间的f之和. l(i)表示i左侧第一个比它大的数的位置,r(i)表示i右侧第一个比它大的数的位置.可以用set处理出来. 把数从大到小排序,依次插入.然后更新l(i),r(i),形成链形结构. 然后对于一个i,向左跳最多K次,将这些位置记录下来,然后向右跳最多K次,每个右侧的位置最多有一个左侧的位置合法.累计答案. #include<cstdio> #include<set> #include<algorithm&g

hdu 6128 Inverse of sum(推公式)

题目链接:hdu 6128 Inverse of sum 题意: 给你n个数,问你有多少对i,j,满足i<j,并且1/(ai+aj)=1/ai+1/aj 在%p意义下. 题解: 不愧是高中生,推公式神题. 将式子通分化简后可得(ai2+aj2+ai*aj)%p=0. 然后两边同时将两边乘(ai-aj),化简可得(ai3-aj3)%p=0. 然后就可以用map记录一下个数,并且减掉ai==aj时不合法的情况就行了. 1 #include<bits/stdc++.h> 2 #define F

HDU 6057 Kanade&#39;s convolution

题目链接:HDU-6057 题意: 思路:先按照官方题解推导出下面的式子: 现在唯一的问题就是怎么解决[bit(x)-bit(y)=bit(k)]的问题. 我们定义\( F(A,k)_{i}=\left[ bit\left( i\right) =k\right] * A_{i} \),相当于把A.B.C分别按照bit划分成m+1个序列. 有如下公式: 同时我们发现\( C_k=F(C,bit(k)))_k \). 然后我们就可以搞出来啦! 代码: 1 #include<iostream> 2

hdu 6057 Kanade&#39;s convolution(子集卷积)

题解: 然后就是接下来如何fwt 也就是如何处理bit(x) - bit(y) = bit(k)这个条件. 其实就是子集卷积. 把bit(x)和bit(y)划分成两个集合,然后就是子集卷积的形式. 这里设两个新的数组 A[bit(y)][y], B[bit(x)][x],代表拆出来的相应数组 然后对这两个数组做fwt,得到其点值表示,然后直接在外层枚举x和y的大小然后做卷积即可. 这样说可能很抽象,其实贴出代码就很清楚了 #include <iostream> #include <vec

hdu 6059 Kanade&#39;s trio(trie+容斥)

题目链接:hdu 6059 Kanade's trio 题意: 给你n个数,让你找有多少个(i,j,k),使得i<j<k满足a[i]^a[j]<a[j]^a[k]. 题解: 首先考虑a[i]和a[k],将他们都转换成二进制,对于a[i]和a[k],我们用Bi[p]表示二进制下的a[i]的第p位.考虑a[i]和a[k]二进制不同的最高位,这里假设为p,如果Bi[p]=0,Bk[p]=1,那么Bj[p]要为0,才能使得a[i]^a[j]<a[j]^a[k].(因为p前面的位相同,只有亦