首页 > 代码库 > bzoj 4069~4071 APIO2015

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\n",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\n",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\n",ans);    return 0;}
View Code

 

bzoj 4069~4071 APIO2015