zoukankan      html  css  js  c++  java
  • 「CCO 2020」购物计划

    「CCO 2020」购物计划

    核心思想:堆+调整临近

    (x_i=y_i=1)

    这个限制相当于每一组内的权值排名可以确定,设组内为(A_{i,j}(jge 1))

    那么我们一个方案的选择可以用(M)个指针(P_i)表示,和为(displaystyle sum A_{i,P_i})

    考虑用调整的方式解决这个问题,大体思路上,我们可以记录当前移动指针(P_p)

    每次可以选择移动(P_p),或者某一个(P_{i},i>p)

    如果直接进行,每次移动的指针数量是(O(m))级别的,显然不可行

    考虑优化一下进行,每次只能选取(i=p+1)

    此时,编号小的会先被移动

    为了保证答案单调性,我们需要将(A_{i,2}-A_{i,1})较小的组先移动

    同时,并不是每一个组都会被移动,因此转移还要支持一个特殊回撤操作,来撤回当前组的指针

    也就是说,若(P_p=2),可以选择把(P_p)回撤为(1),然后将(P_{p+1})改为(2)

    由此,每个点状态可以选择:

    1.移动自己

    2.移动下一个

    3.若(P_p=2),回撤自己,同时移动下一个

    这样的调整法,可以保证每一个状态恰好有一个前驱,且转移过程中值不断变大

    由此可以(O(k))状态数进行调整,用堆维护,复杂度为(O(klog k))

    [ ]

    组内调整

    一个组内会选择若干个数(A_{b_i},iin [1,c])

    初始最小值,显然满足(b_i=i)

    类似的,我们记录当前指针(p),前驱指针(l),后继指针(r)

    显然(p)要往后移,且不能达到(r),因此决策只有两种

    1.移动前驱(l),并将当前指针变为前驱

    2.移动自己(p)

    这样的调整是固定个数的,因此,一开始就把(cin[x_i,y_i])的所有情况插入即可

    [ ]

    最后,将两部分一同进行,每次组间调整时,通过组内调整查询答案

    总的组内和组间调整次数均为(O(k)),状态数分别不超过(2k,3k)

    复杂度为(O(klog k))

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define pb push_back
    #define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
    char IO;
    int rd(){
        int s=0;
        while(!isdigit(IO=getchar()));
        do s=(s<<1)+(s<<3)+(IO^'0');
        while(isdigit(IO=getchar()));
        return s;
    }
    enum{N=200010,LINF=1ll<<60};
    
    int n,m,k,I[N]; ll L;
    struct Group{
        vector <int> A;
        int l,r,c;
        struct Node{
            int l,p,r; ll s;
            bool operator < (const Node &__) const { return s>__.s; }
        };
        priority_queue <Node> que;
        vector <ll> V;
        void Init(){
            l=rd(),r=rd(),sort(A.begin(),A.end()),c=A.size();
            if(c<l) {
                rep(i,1,k) puts("-1");
                exit(0);
            }
            r=min(r,c);
            rep(i,0,l-1) L+=A[i];
            ll s=0;
            if(!l) V.pb(0);
            rep(i,0,c-1) {
                if(i>=r) break;
                s+=A[i];
                if(i>=l-1) que.push((Node){i-1,i,c-1,s});
            }
        }
        void Next(){
            if(que.empty()) return V.pb(LINF);
            Node t=que.top(); que.pop();
            V.pb(t.s);
            if(t.p<t.r) que.push((Node){t.l,t.p+1,t.r,t.s-A[t.p]+A[t.p+1]}); // Move current point
            if(~t.l && t.l<t.p-1) que.push((Node){t.l-1,t.l+1,t.p-1,t.s-A[t.l]+A[t.l+1]}); // Move previous point 
        }
        // get kth sum
        ll operator [] (const int &k){
            while((int)V.size()<k) Next();
            return V[k-1];
        }
    } S[N];
    
    struct Node{
        int x,y; ll s;
        bool operator < (const Node &__) const { return s>__.s; }
    };
    priority_queue <Node> que;
    
    int main(){
        n=rd(),m=rd(),k=rd();
        rep(i,1,n) { int x=rd(); S[x].A.pb(rd()); }
        rep(i,1,m) S[i].Init();
        printf("%lld
    ",L),k--;
        rep(i,1,m) I[i]=i;
        sort(I+1,I+m+1,[&](int x,int y){ return S[x][2]-S[x][1]<S[y][2]-S[y][1]; });
        que.push((Node){1,2,L-S[I[1]][1]+S[I[1]][2]});
        while(k) {
            Node t=que.top(); que.pop();
            if(t.s>=LINF) break;
            k--,printf("%lld
    ",t.s);
            int i=I[t.x],j=I[t.x+1];
            que.push((Node){t.x,t.y+1,t.s-S[i][t.y]+S[i][t.y+1]});// Move current point
            if(j) que.push((Node){t.x+1,2,t.s-S[j][1]+S[j][2]}); // Move next point
            if(t.y==2 && j) que.push((Node){t.x+1,2,t.s-S[i][2]+S[i][1]-S[j][1]+S[j][2]}); 
            // Back current point ,and move next point
        }
        while(k--) puts("-1");
    }
    
  • 相关阅读:
    sychronized面试问题浅析
    打造一款属于自己的web服务器——开篇
    JVM学习总结五——性能监控及故障处理工具
    【转】Git常用命令备忘
    HTTP上传文件探究
    JVM学习总结四——内存分配策略
    JVM学习总结三——垃圾回收器
    JVM学习总结二——垃圾回收算法
    Vue生命周期中mounted和created的区别
    spring org.springframework.web.bind.annotation 常用注解
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14473944.html
Copyright © 2011-2022 走看看