您的位置:首页 > 其它

HDU 6058 Kanade's sum

2017-08-04 16:33 399 查看

2017多校3-3 Kanade’s sum

链表,思维,计数问题

题意

给你一个n的排列,问所有区间第k大的数的和是多少

n为5e5,k为80

思路

对于每一个i,找到他前面k个比他大的,找到后面k个比他大的。这样,a[i]是第k大的区间可以变为:前面0个比他大,后面k个;前面1个,后面k-1个……,统计这样的区间有多少,就是a[i]的贡献。

用链表维护位置,然后从小到大枚举每一个数,在链表上前跳k下,后跳k下,就找到前后k个比他大的数。在将这个数删去。跳的时候,位置做差,就是合法的区间个数:因为将小的数先删了,所以位置做差就是合法区间数。

统计完两侧乘起来,就是这个数的贡献。

复杂度是O(160n)。用set的话多个找前驱后继的log,会T的。

代码

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <iomanip>
#define N n

using namespace std;

const int MAXN=500007;
typedef long long LL;

int v[MAXN], ha[MAXN];
int pr[MAXN], ne[MAXN];
int a[MAXN], b[MAXN];
int main()
{
int T;cin>>T;
while(T--)
{
int n, k;cin>>n>>k;
for(int i=1;i<=N;i++)
{
cin>>v[i];
ha[v[i]]=i;
}
for(int i=0;i<=N+1;i++)
pr[i]=i-1, ne[i]=i+1;
pr[0]=0;
ne[n+1]=n+1;

LL res=0;
for(int i=1;i<=n;i++)
{
int now=ha[i];
int cnt1=0, cnt2=0;
LL ans=0;
while(cnt1<=k&&now>=0)
{
a[++cnt1]=now-pr[now];
now=pr[now];
}
now=ha[i];
while(cnt2<=k&&now<=n)
{
b[++cnt2]=ne[now]-now;
now=ne[now];
}
now=ha[i];
for(int j=1;j<=cnt1;j++)
if(k-j+1>=1&&k-j+1<=cnt2)
ans+=a[j]*b[k-j+1];
res+=ans*v[now];

ne[pr[now]]=ne[now];
pr[ne[now]]=pr[now];

}
cout<<res<<endl;

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: