HDU 6058 Kanade's sum(链表)

http://acm.hdu.edu.cn/showproblem.php?pid=6058

题意:
找出所有区间第K大的值之和。

思路:

又有点贡献值的味道,就是考虑当前这个数贡献了几个区间。

然后往左和往右分别找大于当前数的k-1个数,这样就可以确定区间的个数,这要求我们从小到大找 并且找完之后需要删除这个数,用链表来维护。

删除元素的目的是为了加速,保证了当前查找的元素是最小值,所以只需要跳跃寻找k次就可以。具体看代码。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<sstream>
 6 #include<vector>
 7 #include<stack>
 8 #include<queue>
 9 #include<cmath>
10 #include<map>
11 #include<set>
12 using namespace std;
13 typedef long long ll;
14 typedef pair<int,int> pll;
15 const int INF = 0x3f3f3f3f;
16 const int maxn = 5*1e5 + 5;
17
18 int n, k;
19
20 int a[maxn];
21 int pre[maxn];
22 int nxt[maxn];
23 int pos[maxn];
24
25 int before[maxn];
26 int after[maxn];
27
28 ll solve(int p)
29 {
30     int c1=0,c2=0;
31     for(int i=p; i&&c1<=k; i=pre[i])
32     {
33         before[c1++]=i-pre[i];  //左边i个比当前数大的方法数
34     }
35     for(int i=p; i<=n&&c2<=k; i=nxt[i])
36     {
37         after[c2++]=nxt[i]-i;
38     }
39
40     ll ans=0;
41     for(int i=0;i<c1;i++)  //左边i个,右边k-i+1个
42     {
43         if(k-i-1<c2)
44         {
45             ans+=before[i]*after[k-i-1];
46         }
47     }
48
49     pre[nxt[p]]=pre[p];
50     nxt[pre[p]]=nxt[p];
51
52     return ans;
53 }
54
55 int main()
56 {
57     //freopen("in.txt","r",stdin);
58     int T;
59     scanf("%d",&T);
60     while(T--)
61     {
62         scanf("%d%d",&n,&k);
63         for(int i=1;i<=n;i++)
64         {
65             scanf("%d",&a[i]);
66             pos[a[i]]=i;
67         }
68         for(int i=1;i<=n;i++)
69         {
70             pre[i]=i-1;
71             nxt[i]=i+1;
72         }
73         pre[0]=0; nxt[n+1]=n+1;
74
75         ll ans=0;
76         for(int i=1;i<=n;i++)
77         {
78             ans+=solve(pos[i])*i;
79         }
80         printf("%lld\n",ans);
81     }
82     return 0;
83 }

HDU 6058 Kanade's sum(链表)

时间: 2024-08-10 23:19:00

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

【链表】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