HDU - 6058 Kanade's sum

Bryce1010模板

http://acm.hdu.edu.cn/showproblem.php?pid=6058

/*
思路是:找出每个x为第k大的区间个数有多少
用pos[i]保存当前x的位置,pre[i]表示向x的左侧扩展k个,next[i]表示向x的右侧扩展k个
然后计算出在左侧到右侧这个范围有多少个区间数符合条件
计算出结果后将pre和next后挪以为,接着计算下一个值
*/

#include<bits/stdc++.h>
using namespace std;

#define ll long long
const int MAXN=5e5+10;
ll pos[MAXN+10];
ll pre[MAXN+10];
ll nxt[MAXN+10];
ll l[MAXN+10],r[MAXN+10];
ll n,k,x;

void del(int x)
{
    pre[nxt[x]]=pre[x];
    nxt[pre[x]]=nxt[x];
}



ll cal(ll x)
{
    ll cnt=0;
    ll c1=0,c2=0;

    for(int i=x;i>0;i=pre[i])
    {
        l[++c1]=i-pre[i];
        if(c1==k)break;
    }
    for(int i=x;i<=n;i=nxt[i])
    {
        r[++c2]=nxt[i]-i;
        if(c2==k)break;
    }
    //计算从左侧区间到右侧区间的区间数
    for(int i=1;i<=c1;i++)
    {
        if(k-i+1<=c2)
            cnt=cnt+l[i]*r[k-i+1];
    }
    return cnt;//返回区间数量

}


int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        //ll n,k,x;
        ll ans=0;
        scanf("%lld%lld",&n,&k);
        for(int i=1;i<=n;i++)
        {
            cin>>x;
            pos[x]=i;
            pre[i]=i-1;
            nxt[i]=i+1;
        }
        pre[0]=0;nxt[n+1]=n+1;
        for(int i=1;i<=n;i++)//计算每个x的区间数
        {
            ll cnt=cal(pos[i]);
//            cout<<cnt<<endl;
            ans+=cnt*i;
            del(pos[i]);
        }
        cout<<ans<<endl;
    }

    return 0;
}





posted @ 2018-07-19 09:02  Bryce1010  阅读(46)  评论(0编辑  收藏  举报