您的位置:首页 > 其它

HDU 6058 Kanade's sum (区间第k大的数的贡献)

2017-08-02 16:06 471 查看

思路:

维护一个链表,初始状态为输入的序列。

然后从1开始到n,对每个数统计他在哪些区间中,然后乘以这个数,作为这个数做出的贡献。

统计他在某些区间的办法:

对于每个数i,我们向左找k-1个比他大的数(由于我们是从小到大处理的,且每个数处理后就在链表里删除了,所以这里我们直接一个个跳就好)。假设这第k-1个数为b,再向左找第k个为a,那么我们可以得知,(a,b】中的数皆可作为满足条件的区间的左端点。然后相似的考虑右端点,在这种情况下i的右边第一个比i大的数左边的数都可以作为满足条件的区间的右端点。

然后我们将区间整体向右走一跳。变成左边有k-2个比i大的,右边有1的比i大的,然后同理统计。

区间递推知道左端点为i。

至此我们将i对所有它出现的区间都统计了贡献。

然后我们就可以在链表里删除这个数。

然后接着处理下一个。

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long int lli;
using namespace std;
struct pp{
int tol,tor;
}head[600000];
int lis[600000];
lli a[600000];
// 自适应辛普森
int main(){
//    freopen("1003.in","r",stdin);
//    freopen("my.txt","w",stdout);
int cas,n,k,v;
scanf("%d",&cas);
while(cas--){
scanf("%d%d",&n,&k);
for(int i = 1;i <= n;i++){
scanf("%d",&v);
lis[i] = v;
a[v] = i;
head[i].tol = i-1;
head[i].tor = i+1;
}
head[0].tor = 1;head[n+1].tor = 0;
lis[0] = 0;a[0] = 0;
lis[n+1] = n+1;a[n+1] = n+1;
lli ans = 0;
for(int i = 1;i <= n;i++){
int n1 = a[i],n2,n3 = a[i],j;
for(j = 1;j <= k-1 && n1;j++){
n1 = head[n1].tol;
}
if(!n1){
j--;
n1 = head[n1].tor;
for(;j <= k-1 && n3!=n+1;j++){
n3 = head[n3].tor;
}
if(j != k) break;
}
for(int cnt = 1;cnt <= k && n1 <= a[i] &&n3;cnt++){
if(n3 != n+1)
ans += (lli)i*(lli)(a[lis[n1]]-a[lis[head[n1].tol]])*(lli)(a[lis[head[n3].tor]]-a[lis[n3]]);
n1 = head[n1].tor;   n3 = head[n3].tor;
}
n1 = head[a[i]].tol,n2 = head[a[i]].tor;
head[n1].tor = n2;
head[n2].tol = n1;
}
printf("%lld\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: