hdu 6058

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

题意:求区间第K大然后乘以它本身的总和

思路:枚举X,维护一个链表,这个链表是记录比它小的一些,比他大的有多少个的一个链表

因为在这个链表中隔K个的值,然后取第K大就一定是X

然后维护这个链表呢,就是指已经枚举过的X就不要出现在这个链表里面了,因为如果它的值比这个X要小的话,肯定是不会影响这个第K大的

然后不可能出现比它大的情况,因为我们枚举X是从小到大枚举的,所以这个问题就可以化解

 1 #include <stdio.h>
 2 #include <string.h>
 3 #define maxn 500005
 4
 5 struct Node {
 6     int pre, next;
 7     int val;
 8 }node[maxn];
 9
10 int next[maxn];
11 int pre[maxn];
12
13 int main()
14 {
15     int t, a;
16     int m, k;
17     scanf("%d", &t);
18     while (t--)
19     {
20         scanf("%d%d", &m, &k);
21         for (int i = 1; i <= m; i++) {
22             scanf("%d", &a);
23             node[i].pre = i - 1;
24             node[i].next = i + 1;
25             node[a].val = i;
26         }
27         long long ans = 0;
28         for (int i = 1; i <= m - k+1; i++)
29         {
30             int pos = node[i].val;
31             int pr = 0;
32             int ne = 0;
33             for (int j = pos; j&&pr <= k + 1; j = node[j].pre) pre[++pr] = j; //找到前面比它小的
34             for (int j = pos; j&&ne <= k + 1; j = node[j].next) next[++ne] = j;   //找到后门比它大的
35              pre[++pr] = 0;
36             next[++ne] = m + 1;
37             for (int j = 1; j < pr; j++)
38             {
39                 if (k - j + 1 < ne && k - j + 1 >= 1)
40                 {
41                     ans += (long long)(next[k + 1 - j + 1] - next[k + 1 - j])*(pre[j] - pre[j + 1])*i;   //i一定为这个区间的第K大
42                 }
43             }
44             node[node[pos].pre].next = node[pos].next;   //链表的维护
45             node[node[pos].next].pre = node[pos].pre;
46             node[pos].pre = node[pos].next = 0;
47         }
48         printf("%lld\n", ans);
49     }
50     return 0;
51 }
时间: 2024-10-12 23:57:21

hdu 6058的相关文章

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

hdu 6058 思维

题目:http://acm.hdu.edu.cn/showproblem.php?pid=6058 分析题目的时候,由于枚举的区间很多,而第k大的值范围小,应该要想到去枚举第k大的值然后找到这个值对答案的贡献. 题解:我们只要求出对于一个数x左边最近的k个比他大的和右边最近k个比他大的,扫一下就可以知道有几个区间的kk大值是xx.(这个地方自己举几个例子就知道了) 我们考虑从小到大枚举x,每次维护一个链表(我写了一个双链表),链表里只有大于x的数,每次求x对答案的贡献的时候,直接在链表中x的位置

hdu 6058 To my boyfriend (计算贡献,思维)

题意: 给你一个全排列,要你求这个序列的所有区间的第k大的和 思路:比赛的时候一看就知道肯定是算贡献,也知道是枚举每个数,然后看他在多少个区间是第K大,然后计算他的贡献就可以了,但是没有找到如何在o(k)的时间内找到这k个区间,然后就一直挂机,惨惨惨 感觉官方题解的思路就很棒啊: 我们只要求出对于一个数x左边最近的k个比他大的和右边最近k个比他大的,扫一下就可以知道有几个区间的k大值是x.= 我们考虑从小到大枚举x,每次维护一个链表,链表里只有>=x的数,那么往左往右找只要暴力跳k次,删除也是O

HDU 1711 Number Sequence (简单KMP)

#include <stdio.h> #include <string.h> int next[10005]; int str1[1000005],str2[10005]; void build_next(int len2) { int i=0,j=-1; next[0] = -1; while (i < len2) { if (j==-1 || str2[i] == str2[j]) { i++; j++; if (str2[i] != str2[j]) { next[i]

HDU 6203 ping ping ping [LCA,贪心,DFS序,BIT(树状数组)]

题目链接:[http://acm.hdu.edu.cn/showproblem.php?pid=6203] 题意 :给出一棵树,如果(a,b)路径上有坏点,那么(a,b)之间不联通,给出一些不联通的点对,然后判断最少有多少个坏点. 题解 :求每个点对的LCA,然后根据LCA的深度排序.从LCA最深的点对开始,如果a或者b点已经有点被标记了,那么continue,否者标记(a,b)LCA的子树每个顶点加1. #include<Bits/stdc++.h> using namespace std;

HDU 5542 The Battle of Chibi dp+树状数组

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5542 题意:给你n个数,求其中上升子序列长度为m的个数 可以考虑用dp[i][j]表示以a[i]结尾的长度为j的上升子序列有多少 裸的dp是o(n2m) 所以需要优化 我们可以发现dp的第3维是找比它小的数,那么就可以用树状数组来找 这样就可以降低复杂度 #include<iostream> #include<cstdio> #include<cstring> #include