HDU 6058 链表

来源:互联网 发布:unity3d窗口最大化 编辑:程序博客网 时间:2024/06/17 14:45

题意

给一组数,这一组数包含很多个子序列,求这些子序列第K大元素的和。

题解

观察发现K很小,因此可以从此着手。
首先我们可以观察一下2,3,4,1,5(求第2大的和)这个序列的计算情况

我们可以发现,4出现了三次。因为右边有一个5,如果子序列包含这一个5,然后左边没有比4大的数的时候,4是第2大的数,也就是符合情况的数。这时候,左边有三种情况符合这种条件,即左边没有元素,左边有3,左边有2,3。因此最后结果就是3*1,因此4出现了三次。
根据上述结论,我们就可以针对每个位置的数尝试去向左向右遍历,然后统计符合条件的情况数。需要特别注意的是,由于我们不知道左边有多少个数比这个数大,右边有多少个更大的,因此我们需要枚举,但是不能每次枚举都去扫描,这样会造成超时。正确的做法是,先向左、向右扫描K个比这个数大的数,记录一下位置。然后再去枚举,这时候每次枚举就只需要查询一下数组就可以了,时间复杂度每次是O(1)的。
在扫描的时候我们可以用链表去优化,用链表优化的话,在处理的时候就需要先按数字大小把下标排个序,然后从代表数字小的下标开始扫描,扫描过程中删去比这个数字小的元素(因为这个元素在以后所有的扫描过程中都不会起任何作用)经过这样的优化处理,就可以以1S的时间复杂度通过这道题。

注意事项

数据很水。。

代码

#include<bits/stdc++.h>#define LL long long#define UP(i,l,h) for(int i=l;i<h;i++)#define DOWN(i,h,l) for(int i=h-1;i>=l;i--)#define W(t) while(t)#define MEM(a,b) memset(a,b,sizeof(a))#define INF 0x3f3f3f3f#define MAXN 500010#define COUT(x) cout<<x<<endlusing namespace std;typedef pair<int,int> Node;Node nodes[MAXN];int a[MAXN],nxt[MAXN],bef[MAXN];int main() {    int t,n,k;    scanf("%d",&t);    W(t--) {        scanf("%d%d",&n,&k);        UP(i,0,n) {            scanf("%d",&a[i]);            nodes[i]=Node(a[i],i),nxt[i]=i+1,bef[i]=i-1;        }        sort(nodes,nodes+n);        LL sum=0;        UP(s,0,n) {            int i=nodes[s].second;            int aa[100],bb[100];            MEM(aa,-1),MEM(bb,-1);            int now=i,num=0;            W(now<n) {                if(a[now]>a[i]) num++;                else if(a[now]<a[i]) {                    nxt[bef[now]]=nxt[now];                    bef[nxt[now]]=bef[now];                }                if(aa[num]==-1) aa[num]=now;                if(num==k) {                    break;                }                now=nxt[now];            }            now=i,num=0;            W(now>=0) {                if(a[now]>a[i]) num++;                else if(a[now]<a[i]) {                    nxt[bef[now]]=nxt[now];                    bef[nxt[now]]=bef[now];                }                if(bb[num]==-1) bb[num]=now;                if(num==k) {                    break;                }                now=bef[now];            }            UP(j,0,k+1){                if(k-1-j<0) continue;                if(aa[j]==-1||bb[(k-1)-j]==-1) continue;                int tmpa,tmpb;                if(aa[j+1]!=-1)tmpa=aa[j+1];                else tmpa=n;                if(bb[(k-1)-j+1]!=-1) tmpb=bb[(k-1)-j+1];                else tmpb=-1;//                COUT(tmpa<<" "<<aa[j]<<" "<<bb[(k-1)-j]<<" "<<tmpb<<" "<<a[i]<<" "<<j );                sum+=(LL)(tmpa-aa[j])*(bb[(k-1)-j]-tmpb)*a[i];            }        }        printf("%I64d\n",sum);    }}
原创粉丝点击