bzoj 1835: [ZJOI2010]base 基站选址

来源:互联网 发布:青岛优创数据英语 编辑:程序博客网 时间:2024/06/05 09:26

题意:

用最少代价,按题目要求覆盖所有点。

题解:

不怎么会做,orz状态表示,知道f[i][j]表示前i个,建j个塔i号点必建并且全部覆盖的最小代价。
因为只考虑i前的,所以统计答案就可以多加一个无限远的点,转移到那里就是答案了。
于是有f[i][j]=min(f[k][j1]+cost(k,i))+c[i]
cost(k,i)是k到i中需要补偿的点。
先上暴力dp的代码:

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#define LL long longusing namespace std;const int inf=(1<<28);int f[20010][110],n,k,sum[20010],s[20010],c[20010],w[20010];void cmin(int &x,int y){    if(x==-1) x=y;    x=min(x,y);}int cost(int l,int r){    int ans=0;    for(int i=l+1;i<r;i++)        if(sum[i]+s[i]<sum[r]&&(l==0||sum[l]<sum[i]-s[i])) ans+=w[i];    return ans;}int main(){    scanf("%d %d",&n,&k);    sum[1]=0;    for(int i=2;i<=n;i++) scanf("%d",&sum[i]);//距离     for(int i=1;i<=n;i++) scanf("%d",&c[i]);//建基站费用     for(int i=1;i<=n;i++) scanf("%d",&s[i]);//接受范围     for(int i=1;i<=n;i++) scanf("%d",&w[i]);//补偿费用     n++;sum[n]=inf;c[n]=0;k++;    memset(f,-1,sizeof(f));    f[0][0]=0;    for(int i=1;i<=n;i++)        for(int j=1;j<=min(i,k);j++)        {            for(int k=0;k<i;k++)                if(f[k][j-1]!=-1) cmin(f[i][j],f[k][j-1]+cost(k,i));            f[i][j]+=c[i];        }    int ans=-1;    for(int i=0;i<=k;i++) cmin(ans,f[n][i]);    printf("%d",ans);}

然后可以发现能用线段树优化。
还要开个堆,维护当前接受范围最短的点。
然后二分出不能接受的点的影响范围,线段树随便搞搞用好了。
口胡能力不足,具体代码。
各种SB错误荒废一晚上。
code:

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<queue>#include<algorithm>#define LL long longusing namespace std;struct node{    LL x,i;    bool operator < (node a) const{return a.x<x;}};priority_queue<node> b[110];const LL inf=(1<<29);LL f[20010][110],n,m,sum[20010],s[20010],c[20010],w[20010];struct trnode{    LL lc,rc,c;    LL u;}tr[40010];LL tot=0;void cmin(LL &x,LL y){    if(x==-1) x=y;    x=min(x,y);}void update(LL x){    LL c=tr[x].u,lc=tr[x].lc,rc=tr[x].rc;    //if(!lc) lc=tr[x].lc=++tot;    //if(!rc) rc=tr[x].rc=++tot;    tr[lc].c+=c;tr[rc].c+=c;    tr[lc].u+=c;tr[rc].u+=c;    tr[x].u=0;}void change(LL x,LL l,LL r,LL k,LL c){    //if(!x) x=++tot;    if(l==r){tr[x].c=c;return;}    LL mid=(l+r)/2;    if(tr[x].u!=0) update(x);    if(k<=mid) change(tr[x].lc,l,mid,k,c);    else change(tr[x].rc,mid+1,r,k,c);    tr[x].c=min(tr[tr[x].lc].c,tr[tr[x].rc].c);}void add(LL x,LL l,LL r,LL fl,LL fr,LL c){    //if(!x) x=++tot;    if(l==fl&&r==fr)    {        tr[x].u+=c;        tr[x].c+=c;        return;    }    if(tr[x].u!=0) update(x);    LL mid=(l+r)/2;    if(fr<=mid) add(tr[x].lc,l,mid,fl,fr,c);    else if(fl>mid) add(tr[x].rc,mid+1,r,fl,fr,c);    else add(tr[x].lc,l,mid,fl,mid,c),add(tr[x].rc,mid+1,r,mid+1,fr,c);    tr[x].c=min(tr[tr[x].lc].c,tr[tr[x].rc].c);}LL findans(LL x,LL l,LL r,LL fl,LL fr){    //if(!x) return inf;    if(l==fl&&r==fr) return tr[x].c;    LL mid=(l+r)/2;    if(tr[x].u!=0) update(x);    if(fr<=mid) return findans(tr[x].lc,l,mid,fl,fr);    if(fl>mid) return findans(tr[x].rc,mid+1,r,fl,fr);    return min(findans(tr[x].lc,l,mid,fl,mid),findans(tr[x].rc,mid+1,r,mid+1,fr));}void solve(LL L,LL i){    if(sum[L]>=sum[i]-s[i]) return;    LL l=L,r=i,ans;    while(l<=r)    {        LL mid=(l+r)/2;        if(sum[mid]<sum[i]-s[i]) l=mid+1,ans=mid;        else r=mid-1;    }    add(1,1,n,L,ans,w[i]);}LL bt(LL l,LL r){    //printf("%lld %lld %lld\n",tot,l,r);    LL x=++tot;    tr[x].lc=tr[x].rc=0;tr[x].c=inf;    tr[x].u=0;    if(l!=r)    {        LL mid=(l+r)/2;        tr[x].lc=bt(l,mid);        tr[x].rc=bt(mid+1,r);    }    return x;}int main(){    //freopen("a.in","r",stdin);    scanf("%lld %lld",&n,&m);    sum[1]=0;    for(LL i=2;i<=n;i++) scanf("%lld",&sum[i]);//距离     for(LL i=1;i<=n;i++) scanf("%lld",&c[i]);//建基站费用     for(LL i=1;i<=n;i++) scanf("%lld",&s[i]);//接受范围     for(LL i=1;i<=n;i++) scanf("%lld",&w[i]);//补偿费用     n++;sum[n]=inf;c[n]=0;m++;sum[0]=-inf;c[0]=0;    memset(f,-1,sizeof(f));    tot=0;    for(LL i=0;i<=n;i++) tot+=w[i],f[i][0]=tot;    while(!b[1].empty()) b[1].pop();    tot=0;    for(LL i=1;i<=n;i++)    {        while(!b[1].empty()&&b[1].top().x<sum[i]) tot+=w[b[1].top().i],b[1].pop();//printf("\n");        f[i][1]=tot+c[i];        node tmp;tmp.x=sum[i]+s[i];tmp.i=i;        b[1].push(tmp);    }    for(LL j=2;j<=m;j++)    {        //memset(tr,0,sizeof(tr));        tot=0;bt(1,n);        change(1,1,n,j-1,f[j-1][j-1]);        while(!b[j].empty()) b[j].pop();        for(LL i=j;i<=n;i++)        {            while(!b[j].empty()&&b[j].top().x<sum[i]) solve(j-1,b[j].top().i),b[j].pop();//printf("\n");            f[i][j]=findans(1,1,n,j-1,i-1)+c[i];            change(1,1,n,i,f[i][j-1]);            node tmp;tmp.x=sum[i]+s[i];tmp.i=i;            b[j].push(tmp);        }    }    LL ans=-1;    for(LL i=0;i<=m;i++) cmin(ans,f[n][i]);//,printf("%lld ",f[n][i]);printf("\n");    printf("%lld",ans);}