• 洛谷 P2048 [NOI2010]超级钢琴 || Fantasy


    https://www.luogu.org/problemnew/show/P2048

    http://www.lydsy.com/JudgeOnline/problem.php?id=2006

    首先计算出数列的前缀和数组a[0]..a[n],那么问题转化为:从[0,n]中选取任意两个数(i,j)使得i<j,计算a[j]-a[i];对于所有合法的数对(i,j),求第k大的a[j]-a[i]的值。

    考虑枚举i,对于每一个i要得到第k大的a[j]-a[i],则需要从[i+1,n]中选取j使得a[j]是a[i+1]到a[n]中第k大的。

    用一个优先队列维护一下,然后问题就只剩区间k大了。可以用静态主席树搞一下。

    但是你会发现T到飞起...常数太大了2333333

    本来动态开点偷懒都不行了

     1 #pragma GCC optimize("Ofast")
     2 #pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
     3 #pragma GCC diagnostic error "-fwhole-program"
     4 #pragma GCC diagnostic error "-fcse-skip-blocks"
     5 #pragma GCC diagnostic error "-funsafe-loop-optimizations"
     6 #pragma GCC diagnostic error "-std=c++14"
     7 #include<cstdio>
     8 #include<algorithm>
     9 #include<queue>
    10 #include<tr1/unordered_map>
    11 #define mid ((l+r)>>1)
    12 using namespace std;
    13 typedef long long LL;
    14 typedef pair<LL,int> P;
    15 tr1::unordered_map<LL,int> ma;
    16 LL tmp[500100],ma2[500100];
    17 int mem,lc[40000100],rc[40000100],dat[40000100],root[500100];
    18 LL ll,rr,totn;
    19 LL L;int x;
    20 //root[i]表示[i+L,i+R]区间的线段树,也就是选i+1号为左端点时右端点可取范围
    21 void addx(LL l,LL r,int& num)
    22 {
    23     int t=num;num=++mem;//if(mem>=40000000){puts("test");exit(0);}
    24     lc[num]=lc[t];rc[num]=rc[t];dat[num]=dat[t];
    25     if(l==r)    {dat[num]+=x;return;}
    26     if(L<=mid)    addx(l,mid,lc[num]);
    27     else    addx(mid+1,r,rc[num]);
    28     dat[num]=dat[lc[num]]+dat[rc[num]];
    29 }
    30 LL getx(LL l,LL r,int num)//第x大
    31 {
    32     if(l==r)    return l;
    33     if(dat[rc[num]]>=x)    return getx(mid+1,r,rc[num]);
    34     else    return x-=dat[rc[num]],getx(l,mid,lc[num]);
    35 }
    36 int n,k,lx,rx;LL ans;
    37 LL a[500010];int nownum[500010];
    38 priority_queue<P> q;
    39 //P(当前和,i)(当前和等于[i+L,i+R]的第nownum[i]大-a[i])
    40 //void out(LL l,LL r,LL num)
    41 //{
    42 //    if(l==r)    {for(LL i=1;i<=dat[num];i++)    printf("%lld ",l);return;}
    43 //    out(l,mid,lc[num]);out(mid+1,r,rc[num]);
    44 //}
    45 //void out()
    46 //{
    47 //    queue<P> qq;P t;
    48 //    while(!q.empty())    {t=q.top();q.pop();printf("%lld %lld
    ",t.first,t.second);qq.push(t);}
    49 //    while(!qq.empty())    {t=qq.front();qq.pop();q.push(t);}
    50 //}
    51 int main()
    52 {
    53     int l=0,r=-1,i;P t;
    54     scanf("%d%d%d%d",&n,&k,&lx,&rx);
    55     for(i=1;i<=n;i++)    scanf("%lld",&a[i]),a[i]+=a[i-1],tmp[++tmp[0]]=a[i];
    56     sort(tmp+1,tmp+tmp[0]+1);totn=unique(tmp+1,tmp+tmp[0]+1)-tmp-1;
    57     for(i=1;i<=totn;i++)    ma[tmp[i]]=i,ma2[i]=tmp[i];
    58     for(i=1;i<=n;i++)    a[i]=ma[a[i]];
    59     ll=1;rr=totn;
    60     while(r<n&&r<rx)    r++,L=a[r],x=1,addx(ll,rr,root[0]);
    61     while(l<=n&&l<lx)    L=a[l],x=-1,addx(ll,rr,root[0]),l++;
    62     if(l<=r)
    63     {
    64         x=nownum[0]=1;
    65         q.push(P(ma2[getx(ll,rr,root[0])]-ma2[a[0]],0));
    66     }
    67     for(i=1;i<n;i++)
    68     {
    69         root[i]=root[i-1];
    70         while(r<n&&r<i+rx)    r++,L=a[r],x=1,addx(ll,rr,root[i]);
    71         while(l<=n&&l<i+lx)    L=a[l],x=-1,addx(ll,rr,root[i]),l++;
    72         if(l<=r)
    73         {
    74             x=nownum[i]=1;
    75             q.push(P(ma2[getx(ll,rr,root[i])]-ma2[a[i]],i));
    76         }
    77     }
    78     //out();
    79     //printf("
    %lld",mem);
    80     //return 0;
    81 
    82     for(i=1;i<=k;i++)
    83     {
    84         t=q.top();q.pop();
    85         //printf("a%lld
    ",t.first);
    86         ans+=t.first;
    87         ++nownum[t.second];
    88         //l=min(n+1,t.second+lx);r=min(n,t.second+rx);
    89         //if(r-l+1<nownum[t.second])    continue;
    90         if(dat[root[t.second]]<nownum[t.second])    continue;
    91         x=nownum[t.second];
    92         q.push(P(ma2[getx(ll,rr,root[t.second])]-ma2[a[t.second]],t.second));
    93     }
    94     printf("%lld",ans);
    95 
    96     //for(i=0;i<n;i++)    {out(ll,rr,root[i]);puts("");}
    97     return 0;
    98 }

    错误记录:90行写成dat[t.second];动态开点(没有离散化)时误以为值域只有-1000到1000(但事实上值域是前缀和的值域,-5e8到5e8)

    开了奇怪的Ofast后A掉了....

    其实有更优越的做法,就是维护优先队列时,每次搞完[l,r]区间最大值(在k位置)后,就把它拆成[l,k-1]和[r+1,k](还有这两个区间内分别的最小值)分别放回去,这样恰好去掉了之前的最大值,又不破坏次大值、第三大值、....。这样只需要ST表预处理一下然后RMQ就行了,好写&常数小


    这里有一个一模一样的题,并过来

  • 相关阅读:
    XMEGA IO口外部中断操作
    博客开通了
    cocos2d-x CCParticleSystem粒子系统
    获得web api 返回的Dataset 绑定到网格控件上
    DbHelperSQL—— 动软生成DbHelperSQL类
    Silverlight 调用 web api
    await运算符只能用于异步方法中。请考虑用async修饰符标记此方法,并将其返回类型更改为Task
    js如何获取url的参数
    cvbfbd
    【转】selenium及webdriver的原理
  • 原文地址:https://www.cnblogs.com/hehe54321/p/8586056.html
Copyright © 2020-2023  润新知