HDU 6058 Kanade's sum(链表)
Posted 谦谦君子,陌上其华
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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(链表)的主要内容,如果未能解决你的问题,请参考以下文章
HDU 6058 Kanade's sum —— 2017 Multi-University Training 3
链表2017多校训练3 HDU 6058 Kanade's sum