zoukankan      html  css  js  c++  java
  • bzoj 4069~4071 APIO2015

    T1

    从高到底按位确定答案

    A=1时f[i]表示前i个数合法的划分至少需要分出几段,时间复杂度$O(n^2log(ans))$

    A>1时f[i][j]表示前i个数划分为j段是否可能合法,转移显然,时间复杂度$O(n^3log(ans)/32)$

    #include<cstdio>
    #include<cstring>
    #include<bitset>
    typedef long long i64;
    int n,A,B;
    int f[2007];
    i64 s[2007],ans=0;
    std::bitset<207>d[207];
    int main(){
        scanf("%d%d%d",&n,&A,&B);
        for(int i=1;i<=n;++i)scanf("%lld",s+i),s[i]+=s[i-1];
        if(A==1){
            for(int x=50;x>=0;--x){
                i64 v=ans|((1ll<<x)-1);
                for(int i=1;i<=n;++i){
                    f[i]=0x3f3f3f3f;
                    for(int j=0;j<i;++j)if(((s[i]-s[j])|v)==v&&f[j]+1<f[i])f[i]=f[j]+1;
                }
                if(f[n]>B)ans|=1ll<<x;
            }
        }else{
            d[0][0]=1;
            for(int x=50;x>=0;--x){
                i64 v=ans|((1ll<<x)-1);
                for(int i=1;i<=n;++i){
                    d[i].reset();
                    for(int j=0;j<i;++j)if(((s[i]-s[j])|v)==v)
                    d[i]|=d[j]<<1;
                }
                bool dd=0;
                for(int i=A;i<=B;++i)dd|=d[n][i];
                if(!dd)ans|=1ll<<x;
            }
        }
        printf("%lld
    ",ans);
        return 0;
    }
    View Code

    T2

    对每个不同的(p[i],b[i]%p[i]),新建一些点表示这个i可以走到的位置,每个位置和每个i也建出对应的点

    最后可以转为01边权最短路

    可以证明时空复杂度均为$O(n^frac 3 2)$

    #include<bits/stdc++.h>
    const int inf=0x3f3f3f3f,C=300;
    int n,m,b[30007],p[30007],B;
    struct edge{
        int to;
        edge*nx;
    }*ep=0,*mep=0;
    edge*e0[30007*C];
    int l[30007*C];
    bool is[30007*C];
    void ae(int a,int b){
        if(ep==mep)ep=new edge[10000],mep=ep+10000;
        *ep=(edge){b,e0[a]};
        e0[a]=ep++;
    }
    int idp;
    struct node{int w,l;void upd1(int);};
    std::deque<node>q;
    std::map<int,int>mp;
    void node::upd1(int u){
        if(::l[u]>l+1)q.push_back((node){u,::l[u]=l+1});
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;++i)scanf("%d%d",b+i,p+i);
        idp=n+m;
        for(int i=0;i<m;++i){
            ae(b[i],n+i);
            ae(n+i,b[i]);
            int x=p[i],y=b[i]%x;
            int&z=mp[x<<15|y];
            if(!z){
                z=idp;
                int a;
                for(a=y;a+x<n;a+=x){
                    is[idp]=1;
                    ae(idp++,a);
                }
                ae(idp++,a);
            }
            ae(n+i,z+(b[i]-y)/x);
        }
        std::fill(l,l+idp+1,inf);
        q.push_back((node){n,l[n]=0});
        while(!q.empty()){
            node w=q.front();q.pop_front();
            if(w.l!=l[w.w])continue;
            if(w.w==n+1)return printf("%d
    ",w.l),0;
            for(edge*i=e0[w.w];i;i=i->nx){
                int u=i->to;
                if(l[u]>w.l)q.push_front((node){u,l[u]=w.l});
            }
            if(is[w.w-1])w.upd1(w.w-1);
            if(is[w.w])w.upd1(w.w+1);
        }
        return puts("-1"),0;
    }
    View Code

    T3

    对同侧的直接计算贡献,否则考虑不同侧的

    K=1,中位数位置最优

    K=2,可以证明按$S_i+T_i$排序后划分成左右两部分后按K=1的情况处理,能找到最优解

    带插入的中位数可以用对顶堆维护

    时间复杂度$O(nlogn)$

    #include<bits/stdc++.h>
    typedef long long i64;
    int k,n;
    char s1[2],s2[2];
    int p1,p2,xs[200007],xp=0;
    i64 ans=0;
    int abs(int x){return x>0?x:-x;}
    struct pos{
        int a,b;
        bool operator<(pos w)const{return a+b<w.a+w.b;}
    }ps[100007];
    int pp=0;
    i64 ss1=0,ss2=0,f[100007];
    std::priority_queue<int>q1;
    std::priority_queue<int,std::vector<int>,std::greater<int> >q2;
    void init(){
        q1=std::priority_queue<int>();
        q2=std::priority_queue<int,std::vector<int>,std::greater<int> >();
        ss1=ss2=0;
    }
    void ins(int x){
        if(q1.size()&&x<=q1.top()){
            q1.push(x),ss1+=x;
            if(q1.size()>q2.size()+1){
                int x=q1.top();q1.pop();
                ss1-=x;ss2+=x;
                q2.push(x);
            }
        }else{
            q2.push(x),ss2+=x;
            if(q2.size()>q1.size()+1){
                int x=q2.top();q2.pop();
                ss2-=x;ss1+=x;
                q1.push(x);
            }
        }
    }
    void mins(i64&a,i64 b){if(a>b)a=b;}
    i64 cal(){
        return ss2-ss1;
    }
    int main(){
        scanf("%d%d",&k,&n);
        if(k==1){
            for(int t=0;t<n;++t){
                scanf("%s%d%s%d",s1,&p1,s2,&p2);
                if(s1[0]==s2[0])ans+=abs(p2-p1);
                else ++ans,xs[xp++]=p1,xs[xp++]=p2;
            }
            if(xp){
                std::nth_element(xs,xs+xp/2,xs+xp);
                int x=xs[xp/2];
                for(int a=0;a<xp;++a)ans+=abs(xs[a]-x);
            }
        }else{
            for(int t=0;t<n;++t){
                scanf("%s%d%s%d",s1,&p1,s2,&p2);
                if(s1[0]==s2[0])ans+=abs(p2-p1);
                else ++ans,ps[pp++]=(pos){p1,p2};
            }
            std::sort(ps,ps+pp);
            if(pp){
                init();
                for(int a=0;a<pp;++a){
                    ins(ps[a].a);ins(ps[a].b);
                    f[a]=cal();
                }
                i64 mx=f[pp-1];
                init();
                for(int a=pp-1;a;--a){
                    ins(ps[a].a);ins(ps[a].b);
                    mins(mx,cal()+f[a-1]);
                }
                ans+=mx;
            }
        }
        printf("%lld
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    IPC机制key值的各位组成
    ctrl+c,ctrl+d,ctrl+z在linux中意义
    Linux x86_64与i386区别之 —— 内存寻址
    readdir_r()读取目录内容
    memmove和memcpy
    sscanf的应用
    获取CPU频率
    盘点十个超级实用的 JS 特性
    Java 类在 Tomcat 中是如何加载的?
    Java 类在 Tomcat 中是如何加载的?
  • 原文地址:https://www.cnblogs.com/ccz181078/p/6843512.html
Copyright © 2011-2022 走看看