hdu 6058 Kanade'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 #define F(i,a,b) for(int i=a;i<=b;++i)
 3 using namespace std;
 4 typedef long long ll;
 5
 6 const int N=5e5+7;
 7 int t,n,k,a[N],idx[N];
 8 struct Node{int pre,nxt,idx;}node[N];
 9
10 int main(){
11     scanf("%d",&t);
12     while(t--)
13     {
14         scanf("%d%d",&n,&k);
15         F(i,1,n)
16         {
17             scanf("%d",a+i),idx[a[i]]=i;
18             node[i]=Node{i-1,i+1,i};
19         }
20         node[n+1].idx=n+1;
21         ll ans=0;
22         F(i,1,n)
23         {
24             int l=idx[i],r=idx[i];
25             int cntl=1,cntr=0;
26             while(cntl<k)
27             {
28                 if(node[l].pre==0)break;
29                 cntl++,l=node[l].pre;
30             }
31             while(cntl)
32             {
33
34                 while(cntr+cntl>k){cntr--,r=node[r].pre;}
35                 while(cntl+cntr<k)
36                 {
37                     if(node[r].nxt==n+1)break;
38                     cntr++,r=node[r].nxt;
39                 }
40                 if(cntl+cntr==k)
41                 {
42                     int L=node[l].idx-node[node[l].pre].idx;
43                     int R=node[node[r].nxt].idx-node[r].idx;
44                     ans+=1ll*L*R*i;
45                 }
46                 l=node[l].nxt,cntl--;
47             }
48             node[node[idx[i]].pre].nxt=node[idx[i]].nxt;
49             node[node[idx[i]].nxt].pre=node[idx[i]].pre;
50         }
51         printf("%lld\n",ans);
52     }
53     return 0;
54 }

hdu 6058 Kanade's sum(链表)

时间: 2024-08-09 06:35:18

hdu 6058 Kanade's sum(链表)的相关文章

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,这样维护一个双向链表,保证链表中的数就是

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

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-6058 Kanade&#39;s sum

题意:略 思路:要我们求每个区间第K大数之和,其实可以转换为求多少个区间的第K大数是X,然后我们在求和就好了. 那么我们可以从小到大枚举所有可能成为第K大的数.为什么从小到大呢? 因为从小到大我们就略去了大小的比较了,后面我们维护的链表就要把这个值除去. /* gyt Live up to every day */ #include<cstdio> #include<cmath> #include<iostream> #include<algorithm>

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