zoukankan      html  css  js  c++  java
  • poj 1160 Post Office(dp + wqs二分)

    题意

    有p个邮局,n个村庄,邮局只能建在村庄里,

    求令所有寄信距离之和最短的值。、

    SOLUTION:

    首先可以n3的dp

    dp i ,j  表示前 i 个地方建立 j 个邮局的最小花费,

    在处理出在任意一个区间建立一个邮局是的最小花费(一个区间放一个邮局的话,放在中位数的位置最有)

    在想如何优化dp

    wqs 二分消掉一维

    设f(x) = g(x) + kx,每次的设立一个邮局都要增加k的价值,看一下当前f(x)的取到最大时和x和题目要求p的关系

    CODE:

    #include <iostream>
    
    #include <algorithm>
    
    #include <cstring>
    
    #include <cstdio>
    
    #include <cmath>
    
    #include <set>
    
    #include <map>
    
    #include <vector>
    
    #include <stack>
    
    #include <queue>
    
    #include <functional>
    
    const int INF=0x3f3f3f3f;
    
    const int maxn=300+10;
    
    const int mod=1e9+7;
    
    const int MOD=998244353;
    
    const double eps=1e-7;
    
    typedef long long ll;
    
    #define vi vector<int>
    
    #define si set<int>
    
    #define pii pair<int,int>
    
    #define pi acos(-1.0)
    
    #define pb push_back
    
    #define mp make_pair
    
    #define lowbit(x) (x&(-x))
    
    #define sci(x) scanf("%d",&(x))
    
    #define scll(x) scanf("%lld",&(x))
    
    #define sclf(x) scanf("%lf",&(x))
    
    #define pri(x) printf("%d",(x))
    
    #define rep(i,j,k) for(int i=j;i<=k;++i)
    
    #define per(i,j,k) for(int i=j;i>=k;--i)
    
    #define mem(a,b) memset(a,b,sizeof(a))
    
    using namespace std;
    
    //dp[i][j]代表前i个村庄 需要j个邮局的最小花费
    
    //
    
    int n,p,a[maxn],sum[maxn],dis[maxn][maxn];
    int c[maxn];
    int dp[maxn];
    inline int check(int mid)
    {
        for(int i=1;i<=n;i++)
            dp[i]=1e16;
        dp[0]=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=i;j++)
            {
                if(dp[i]>dp[j-1] + dis[j][i] + mid)
                {
                    dp[i]=dp[j-1] + dis[j][i] + mid;
                    c[i]=c[j-1]+1;
                }
            }
        }
        //for(int i=1;i<=n;i++)cout<<dp[i]<<" ";cout<<endl;
        return c[n];
    }
    void work()
    {
        int l=-1e9,r=1e9;int ans=0;
        while(l<=r)
        {
            int mid=l+r>>1;
            if(check(mid)<=p)ans=mid,r=mid-1;
            else l=mid+1;
          //  cout<<mid<<" "<<check(mid)<<endl;
        }
        check(ans);
        long long t = dp[n] - p*ans;
        cout<<t<<endl;
    }
    int main()
    
    {
    
        while(~scanf("%d%d",&n,&p))
    
        {
    
            rep(i,1,n)sci(a[i]);
    
            sort(a+1,a+n+1);
    
            sum[0]=0;
    
            rep(i,1,n)sum[i]=sum[i-1]+a[i];
    
            rep(i,1,n)
    
            {
    
                dis[i][i]=0;
    
                rep(j,i+1,n)
    
                {
    
                    int mid=(i+j)/2;
    
                    //画图可证明 坐标零点挪动为a[mid]的前缀和 可理解成每个相加 最后提出a[mid]
    
                    //sum[j]-sum[mid]为[mid+1,j]的求和,sum[mid-1]-sum[i-1]为[i,mid-1]的求和
    
                    dis[i][j]=(sum[j]-sum[mid])-(j-mid)*a[mid]+(mid-i)*a[mid]-(sum[mid-1]-sum[i-1]);
    
                }
    
            }
    
            work();
    
    
        }
    
        return 0;
    
    }
    

      

  • 相关阅读:
    那些H5用到的技术(4)——弹幕
    Android自动化之AccessibilityService
    那些H5用到的技术(3)——屏幕场景滑动
    更新Mac双系统多分区
    那些H5用到的技术(2)——音频和视频播放
    那些H5用到的技术(1)——素材加载
    openstf安装手记
    我的2016年总结
    与为知笔记融合-博客园装修笔记
    点击劫持(click jacking)
  • 原文地址:https://www.cnblogs.com/zhangbuang/p/11236340.html
Copyright © 2011-2022 走看看