zoukankan      html  css  js  c++  java
  • 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);
    }
     
     
     
    
  • 相关阅读:
    记一下后续要看的点
    vue 封装request.js
    shuf命令简单用法
    Redis string 字符串
    Redis 事务操作
    Redis Zset 有序集合
    php操作redis的一些基本操作
    pytest自动化测试入门介绍
    idea&myeclipse 自动生成serialVersionUID
    leetCode1104. 二叉树寻路(medium)
  • 原文地址:https://www.cnblogs.com/chasedeath/p/11743456.html
Copyright © 2011-2022 走看看