• hdu 6058 Kanade's sum


    题意:给出一个从1~n的数列,任意排列,求任意区间的第K大的数之和

    思路:把求任意区间第K大转化为对某一个数x而言,作为第K大时对区间数量的贡献;通过预处理先记录下每个数的位置,设置两个数组left[],和right[],分别记录x左边和右边比x大的数的位置,这样对枚举的每一个x而言,只需要扫一遍左k和右k个数即可,如果枚举的时候从大到小,可以发现前面添加的数都是比当前x大的;可以发现对于x而言左边舍弃一个比它大的值,右边添加一个比它的值,区间依旧满足x第k大;

    附上借鉴一位大牛写的代码:

    #include<iostream>
    #include<cstdio>
    #include<set>
    using namespace std;
    const int maxn=500005;
    typedef long long ll;
    int n,k;
    int le[maxn],ri[maxn],vis[maxn];
    const int read()
    {
        int f=1,x=0;
        char ch=getchar();
        while(ch<'0' || ch>'9'){if(ch=='-')f*=-1;ch=getchar();}
        while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return f*x;
    }
    
    ll sol()
    {
        set<int>s;
        set<int>::iterator it;
        s.insert(0);
        s.insert(n+1);
        ll ans=0;
        for(int i=n;i>0;i--)
        {
            int l,r;
            s.insert(vis[i]);
            it=s.find(vis[i]);
            it++;
            r=*it;
            l=le[r];
            le[r]=vis[i];
            ri[vis[i]]=r;
            ri[l]=vis[i];
            le[vis[i]]=l;
            int nowl=vis[i];
            for(int j=0;j<k&&nowl;j++)
                nowl=le[nowl];
            int nowr=nowl;
            for(int j=0;j<k&&nowr!=n+1;j++)
                nowr=ri[nowr];
            for(int j=0;j<k;j++)
            {
                if(nowl==vis[i] || nowr==n+1)
                    break;
                ans+=1ll*(ri[nowl]-nowl)*(ri[nowr]-nowr)*i;
                nowl=ri[nowl];
                nowr=ri[nowr];
            }
        }
        return ans;
    }
    
    int main()
    {
        freopen("input.txt","r",stdin);
        int cas;
        for(scanf("%d",&cas);cas;cas--)
        {
            scanf("%d%d",&n,&k);
            for(int i=1;i<=n;i++)
            {
                int x=read();
                vis[x]=i;
                le[i]=0;
                ri[i]=n+1;
            }
            if(k<1)
            {
                printf("0
    ");
                continue;
            }
            le[n+1]=0;ri[n+1]=n+1;
            ll ans=sol();
            cout<<ans<<endl;
        }
        return 0;
    }
  • 相关阅读:
    ListView控件学习系列2编辑ListView(Edit,Update,Insert,Delete)
    程序员如何营销自己?(转贴)
    ListView使用技巧
    ListView控件学习系列1了解ListView控件
    LINQ To SQL深入学习系列之四(LINQ查询基础)
    单元测试基础知识(转)
    微软vs2008快捷键
    ListView控件学习系列3ListView选择,排序,分页
    反射学习系列1反射入门
    一道笔试题的解法和联想
  • 原文地址:https://www.cnblogs.com/MeowMeowMeow/p/7275374.html
Copyright © 2020-2023  润新知