其实今天本来没打算写这道题的..不过本蒟蒻刷题的时候看见此题时以为会是一个图上dp什么的..构建了好久图的递推式都没成功,看了下面这个大佬的题解才想明白。(没注意到是在同一直线的性质..)
http://blog.youkuaiyun.com/mlzmlz95/article/details/43890273
自己还是弱啊
题目描述
有N个村庄坐落在一条直线上,第i(i>1)个村庄距离第1个村庄的距离为Di。需要在这些村庄中建立不超过K个通讯基站,在第i个村庄建立基站的费用为Ci。如果在距离第i个村庄不超过Si的范围内建立了一个通讯基站,那么就成它被覆盖了。如果第i个村庄没有被覆盖,则需要向他们补偿,费用为Wi。现在的问题是,选择基站的位置,使得总费用最小。
输入输出格式
输入数据 (base.in) 输入文件的第一行包含两个整数N,K,含义如上所述。 第二行包含N-1个整数,分别表示D2,D3,…,DN ,这N-1个数是递增的。 第三行包含N个整数,表示C1,C2,…CN。 第四行包含N个整数,表示S1,S2,…,SN。 第五行包含N个整数,表示W1,W2,…,WN。
输出文件中仅包含一个整数,表示最小的总费用。
100%的数据中,K<=N,K<=100,N<=20,000,Di<=1000000000,Ci<=10000,Si<=1000000000,Wi<=10000。
题目里的Di是递增的其实已经给了提示了..按照村庄从前往后DP是满足无后效型的。
设f[i]为在第i个村庄建通讯基站时的最小花费。
f[i]=min{f[j]+cost[j][i]}+c[i],1<=j<=i-1
cost[j][i]表示最后两个基站分别建在j和i时对于中间村庄的补偿W之和。
暴力求cost[j][i]的话,时间复杂度会达到O(n^3),对于本题的数据规模来说是不令人满意的。
假如f[j]与cost[j][i]为定值的话,显然可以用数据结构来维护min(f[j]+cost[j][i])
然而当i变为i+1时,cost[j][i]的值会变更,因为此时的基站的位置改变,需要给出的补偿也会改变。
那么这个变化显然是由向右最远为i的村庄所影响的,所以我们可以计算出每个村庄的左端点与右端点l与r,每次转移对于r[x]==i的村庄,将[1,l[x]-1]的区间加上w[x]。
此外,由于答案最优时不一定需要在最后一个点建基站,我们可以新增一个点,w[++n]=+oo,c[n]=0,++k。
这样子就可以保证答案一定是f[n]。
最外层循环基站个数从1到k时注意每次保留最优解,因为不一定建k个基站是最优的。
#include<bits/stdc++.h>
#define fer(i,j,n) for(int i=j;i<=n;i++)
#define far(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
const int maxn=40010;
const int INF=1e9+7;
const int mod=100003;
using namespace std;
/*----------------------------------------------------------------------------*/
inline int read()
{
char ls;int x=0,sng=1;
for(;ls<'0'||ls>'9';ls=getchar())if(ls=='-')sng=-1;
for(;ls>='0'&&ls<='9';ls=getchar())x=x*10+ls-'0';
return x*sng;
}
/*----------------------------------------------------------------------------*/
struct kaga
{
int minn,lazy,l,r;
}tr[maxn<<2];
int n,k,d[maxn],c[maxn],s[maxn],w[maxn],f[maxn],l[maxn],r[maxn];
vector<int> g[maxn];
int ans=INF;
void minup(int x)
{
tr[x].minn=min(tr[x<<1].minn,tr[x<<1|1].minn);
}
void pushdown(int x)
{
int t=tr[x].lazy;
if(tr[x].lazy)
{
tr[x<<1].lazy+=t;
tr[x<<1|1].lazy+=t;
tr[x<<1].minn+=t;
tr[x<<1|1].minn+=t;
}
tr[x].lazy=0;
}
int query(int x,int L,int R)
{
if(L>R)return 0;
pushdown(x);
int l=tr[x].l,r=tr[x].r,mid=(l+r)>>1;
if(l==L&&r==R)
return tr[x].minn;
if(R<=mid)return query(x<<1,L,R);
else if(L>mid)return query(x<<1|1,L,R);
else return min(query(x<<1,L,mid),query(x<<1|1,mid+1,R));
}
void update(int x,int L,int R,int v)
{
//cout<<l<<" "<<r<<endl;
if(L>R)return ;
pushdown(x);
int l=tr[x].l,r=tr[x].r,mid=(l+r)>>1;
if(l==L&&r==R)
{
tr[x].minn+=v;
tr[x].lazy+=v;
return ;
}
if(R<=mid)update(x<<1,L,R,v);
else if(L>mid)update(x<<1|1,L,R,v);
else update(x<<1,L,mid,v),update(x<<1|1,mid+1,R,v);
minup(x);
}
void build(int x,int l,int r)
{
//cout<<x<<" "<<l<<" "<<r<<endl;
tr[x].l=l;tr[x].r=r;
int mid=(l+r)>>1;
if(l==r)
{
tr[x].minn=f[l];
tr[x].lazy=0;
return ;
}
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
minup(x);
tr[x].lazy=0;
}
int main()
{
n=read();k=read()+1;
fer(i,2,n)d[i]=read();
fer(i,1,n)c[i]=read();
fer(i,1,n)s[i]=read();
fer(i,1,n)w[i]=read();
d[++n]=INF;
w[n]=INF;
fer(i,1,n)
{
l[i]=lower_bound(d+1,d+n+1,d[i]-s[i])-d;
r[i]=lower_bound(d+1,d+n+1,d[i]+s[i])-d;
if(d[r[i]]>d[i]+s[i])--r[i];
g[r[i]].push_back(i);
}
fer(i,1,k)
{
//cout<<"wtf";
if(i==1)
{
int t=0;
fer(j,1,n)
{
f[j]=t+c[j];
int sz=g[j].size()-1;
fer(kk,0,sz)t+=w[g[j][kk]];
}
ans=f[n];
continue;
}
build(1,1,n);
fer(j,1,n)
{
f[j]=query(1,1,j-1)+c[j];
int sz=g[j].size()-1;
fer(kk,0,sz)update(1,1,l[g[j][kk]]-1,w[g[j][kk]]);
}
ans=min(ans,f[n]);
}
cout<<ans;
}