6058 Kanade'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;
typedef long long ll;
const int N=1e6+5;
int a[N],b[N],n,k;
int pre[N],nxt[N],pos[N];
ll solve(int x)
{
    int c1=0,c2=0;
    for(int i=x;i&&c1<=k;i=pre[i])
        a[++c1]=i-pre[i];
    for(int i=x;i<=n&&c2<=k;i=nxt[i])
        b[++c2]=nxt[i]-i;
    ll res=0;
    for(int i=1;i<=c1;i++)
    {
        if(c2>=k-i+1&&k-i+1>=1)
            res+=a[i]*b[k-i+1];
    }
    return res;
}
void del(int x)
{
    pre[nxt[x]]=pre[x];
    nxt[pre[x]]=nxt[x];
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        int x;
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
            scanf("%d",&x),pos[x]=i;
        ll ans=0;
        for(int i=0;i<=n+1;i++)
            pre[i]=i-1,nxt[i]=i+1;
        pre[0]=0,nxt[n+1]=n+1;
        for(int i=1;i<=n;i++)
        {
            ans+=i*solve(pos[i]);
            del(pos[i]);
        }
        printf("%lld\n",ans);
    }
    return 0;
} 

6058 Kanade's sum 链表维护()

时间: 2024-10-01 20:29:01

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

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 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

【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>

BZOJ1150 [CTSC2007]数据备份Backup 【堆 + 链表】

题目 你在一家 IT 公司为大型写字楼或办公楼(offices)的计算机数据做备份.然而数据备份的工作是枯燥乏味 的,因此你想设计一个系统让不同的办公楼彼此之间互相备份,而你则坐在家中尽享计算机游戏的乐趣.已知办公 楼都位于同一条街上.你决定给这些办公楼配对(两个一组).每一对办公楼可以通过在这两个建筑物之间铺设网 络电缆使得它们可以互相备份.然而,网络电缆的费用很高.当地电信公司仅能为你提供 K 条网络电缆,这意味 着你仅能为 K 对办公楼(或总计2K个办公楼)安排备份.任一个办公楼都属于唯一

【hdu5381】维护区间内所有子区间的gcd之和-线段树

题意:给定n个数,m个询问,每次询问一个区间内所有连续子区间的gcd的和.n,m<=10^5 题解: 这题和之前比赛的一题很像.我们从小到大枚举r,固定右端点枚举左端点,维护的区间最多只有log段.为什么?以为长区间的gcd肯定是短区间gcd的约数,并且要是不同的话至少要/2,最多那就只有log数值这么多段.还有,相同gcd的区间一定是连续的若干个(想想gcd是怎么求的就知道了).线段树每个端点x维护的是以x为左端点,r从1到当前的r的gcd的和.链表维护log段数,然后每次加到线段树里更新.

聊聊高并发(三十二)实现一个基于链表的无锁Set集合

Set表示一种没有反复元素的集合类,在JDK里面有HashSet的实现,底层是基于HashMap来实现的.这里实现一个简化版本号的Set,有下面约束: 1. 基于链表实现.链表节点依照对象的hashCode()顺序由小到大从Head到Tail排列. 2. 如果对象的hashCode()是唯一的.这个如果实际上是不成立的,这里为了简化实现做这个如果.实际情况是HashCode是基于对象地址进行的一次Hash操作.目的是把对象依据Hash散开.所以可能有多个对象地址相应到一个HashCode.也就是