zoukankan      html  css  js  c++  java
  • uoj #49. [UR #3] 铀仓库

    题目链接

    题意:数轴上某些点有若干物品,任选起点在规定时间T内移动到附近将一个物品取回起点。移动单位距离的时间代价为1,取物品不需付出时间,求最多保留的物品

    算法:二分答案+贪心判断

    知道做法之后思路是很清晰的,难的是想出正解还有实现时处理好各种细节

    原比赛题解

    CYC题解

    二分答案之后将求值转化为判断

    几个问题:

    1.如何判断:在时间T内,能否取到x的值(物品)

    易得取的必是连续的一段区间

    从左到右枚举起点,易知起点离左边越来越远,离右边越来越近,则该区间一定是单调不下降的

    所以每次移动起点,就贪心地比较左右边界(到起点的距离)。

    若右边更优,则舍弃左边;直到左边界比右边界更优,此时如果再去移动区间的话,就变成了用左边的优值去交换右边的差值,继续向右拓展只会取到更劣的解。

    这样对于每个起点(x=p),就能O(p)地找到最优的区间

    2.记录区间的起点、左右边界之后,如何O(1)地求出付出的时间代价

    需要简单的数学技巧。

    读入时维护a数组的前缀和cnt,以及a*x的前缀和sum

    sum数组是解决问题的关键,其数学意义即为在求从起点往位置x[i]移动时,需要付出的代价即为(取的个数*距离)

    经过数学变换可推出

    cost=(cnt[st]-cnt[l])*x[st]-(sum[st]-sum[l])+l_num*(x[st]-x[l])+r_num*(x[r]-x[st])-(cnt[r-1]-cnt[st])*x[st]+(sum[r-1]-sum[st]);

    1 cost=(cnt[st]-cnt[l])*x[st]-(sum[st]-sum[l])+l_num*(x[st]-x[l])+     //Left
    2       r_num*(x[r]-x[st])-(cnt[r-1]-cnt[st])*x[st]+(sum[r-1]-sum[st]);//Right
    3 对于左半区间:用区间内权值的和*起点坐标,利用sum数组减去多余的值;
    4               左端点的代价可以直接求出
    5 右半区间同理。 
    简单说明?其实是我数学差

    最后由于往返,代价*2

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cctype>
     4 #include<algorithm>
     5 using namespace std;
     6 #define maxn 500010
     7 #define ll long long
     8 ll n,t;
     9 ll cnt[maxn],sum[maxn],x[maxn],a[maxn];
    10 ll read(){
    11     ll x=0;char ch=getchar();
    12     while (!isdigit(ch)){ch=getchar();}
    13     while (isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    14     return x;
    15 }
    16 void init(){
    17     n=read(),t=read();
    18     for (int i=1;i<=n;i++) x[i]=read();
    19     for (int i=1;i<=n;i++) a[i]=read();
    20     for (int i=1;i<=n;i++) cnt[i]=cnt[i-1]+a[i],sum[i]=sum[i-1]+a[i]*x[i];
    21 }
    22 bool ok(int goal){
    23     ll l=1,r=lower_bound(cnt+1,cnt+n+1,goal)-cnt,l_num=a[1],r_num=goal-cnt[r-1],d1,d2,now,cost;
    24     for (int st=1;st<=n;st++){
    25         while (l<st&&r<=n){
    26             int d1=x[st]-x[l],d2=x[r]-x[st];
    27             if (d1>d2){
    28                 now=min(l_num,a[r]-r_num);
    29                 l_num-=now,r_num+=now;
    30                 if (l_num==0) l++,l_num=a[l];
    31                 if (r_num==a[r]) r++,r_num=0;
    32             }else break;
    33         }
    34         cost=(cnt[st]-cnt[l])*x[st]-(sum[st]-sum[l])+l_num*(x[st]-x[l])
    35              +r_num*(x[r]-x[st])-(cnt[r-1]-cnt[st])*x[st]+(sum[r-1]-sum[st]);
    36         cost<<=1;if (cost<=t) return 1;
    37     }             
    38     return 0;
    39 }               
    40 int main(){
    41     init();
    42     ll left=0,right=cnt[n]+1,mid=(left+right)>>2;
    43     while (left<right){
    44         mid=(left+right)>>1;
    45         if (ok(mid)) left=mid+1;
    46         else right=mid;
    47     }
    48     printf("%lld
    ",left-1);
    49     return 0;
    50 }
    View Code
  • 相关阅读:
    FZOJ2115+月赛+多项式
    Statistical Data Mining Tutorials [转]
    码农何去何从
    关于InnoDB索引长度限制的tips
    虚拟化、云计算、开放源代码及其他
    互联网开放平台应用综述
    2012.09月面试五十题
    linux运维常用命令
    Linux 性能测试与分析转
    "Principles of Computer Systems Design"
  • 原文地址:https://www.cnblogs.com/vincent-hwh/p/7354441.html
Copyright © 2011-2022 走看看