1473. [Ioi2000]Post加强版 n log^2 n做法

1473. [Ioi2000]Post加强版 n log^2 n做法

题面

有n个城市从负方向向正方向按照1至n标号,\(d[i]\)表示城市i离原点的距离并且\(d[1] = 0\),对于\(i \ne j\)\(d[i] \ne d[j]\)。城市\(i\)里的居民人数为\(w[i]\),如果每个居民的信件需要投放到\(dis\)以外的邮局去,那么政府为了该城市的居民投放信件将总花费\(w[i] * dis\)的资金。另外,在城市\(i\)建立邮局的费用为\(c[i]\)。 找出一种方案,使得总花费最小。

是一道好题,但是如果只写\(n^2\)就是一道裸题了

\(subtask1 : n \leq 1000\)

 
int n;
 
ll c[N],w[N],d[N],ds[N],s[N];
ll dp[N];
 
 
int main() {
    n=rd();
    rep(i,1,n) d[i]=rd();
    rep(i,1,n) c[i]=rd();
    rep(i,1,n) w[i]=rd();
    d[0]=-1e9;
    d[n+1]=1e9;
    rep(i,1,n+1) {
        ds[i]=ds[i-1]+d[i]*w[i];
        s[i]=s[i-1]+w[i];
    }
    int pre=0;
    rep(i,1,n+1) {
        dp[i]=1e15;
        int mid=i;
        drep(j,i-1,pre) {
            while(mid>=j && d[i]-d[mid] <= d[mid]-d[j]) mid--;
            ll t=dp[j];
            t+=d[i]*(s[i]-s[mid])-(ds[i]-ds[mid]);
            t+=ds[mid]-ds[j]-(s[mid]-s[j])*d[j];
            if(t<dp[i]) dp[i]=t,pre=j;
        }
        dp[i]+=c[i];
    }
    printf("%lld\n",dp[n+1]);
}
 

拓展!!!

\(subtask2 : n \leq 10^5\)

决策单调性求解

单调性比较明显:对于每一个\(i\),决策点为\(j\),那么有随着\(i\)的递增,\(j\)也递增

但是受于转移顺序的限制,我们无法直接套用分治单调性求解

那么如何做呢?

我们再套一层分治!

第一层分治,我们考虑\([l,mid]\)中的dp值对于\([mid+1,r]\)\(dp\)值的贡献

第二层分治,用于完成上述问题

注意一下调用顺序

#include<cstdio> 
#include<cctype>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
 
 
#define reg register
typedef long long ll;
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)
  
 
char IO;
int rd(){
    int s=0,f=0;
    while(!isdigit(IO=getchar())) if(IO=='-') f=1;
    do s=(s<<1)+(s<<3)+(IO^'0');
    while(isdigit(IO=getchar()));
    return f?-s:s;
}
 
 
const int N=3e5+10;
 
 
 
int n;
 
ll c[N],w[N],d[N],ds[N],s[N];
ll dp[N];
int pos[N];
 
void Solve2(int l,int r,int L,int R) {
    if(l>r) return;
    int mid=(l+r)>>1;
    ll mi=1e18,id=-1;
    rep(i,L,R) {
        int p=pos[(d[i]+d[mid])/2];
        ll t=dp[i]+c[mid]+(ds[p]-ds[i])-d[i]*(s[p]-s[i])+d[mid]*(s[mid]-s[p])-(ds[mid]-ds[p]);
        if(mi>t) mi=t,id=i;
    }
    dp[mid]=min(dp[mid],mi);
    if(id==-1) return;
    Solve2(l,mid-1,L,id);
    Solve2(mid+1,r,id,R);
}
 
void Solve1(int l,int r) {
    if(l==r) return;
    int mid=(l+r)>>1;
    Solve1(l,mid);
    Solve2(mid+1,r,l,mid+1);
    Solve1(mid+1,r);
}
 
int main() {
    n=rd();
    rep(i,1,n) d[i]=rd();
    rep(i,1,n) c[i]=rd();
    int p=1;
    rep(i,0,3e5) if(d[p]==i) pos[i]=p,p++;
    else pos[i]=pos[i-1];
    rep(i,1,n) w[i]=rd();
    rep(i,1,n) {
        ds[i]=ds[i-1]+d[i]*w[i];
        s[i]=s[i-1]+w[i];
    }
    rep(i,1,n) dp[i]=d[i]*s[i]-ds[i]+c[i];
    Solve1(1,n);
    ll ans=1e18;
    rep(i,1,n) ans=min(ans,dp[i]+(ds[n]-ds[i])-d[i]*(s[n]-s[i]));
    printf("%lld\n",ans);
}
 
 
 
posted @ 2019-10-26 15:51  chasedeath  阅读(280)  评论(0编辑  收藏  举报