• ZOJ 3627 Treasure Hunt II (贪心,模拟)


    题意:有n个城市并排着,每个城市有些珠宝,有两个人站在第s个城市准备收集珠宝,两人可以各自行动,但两人之间的距离不能超过dis,而且每经过一个城市就需要消耗1天,他们仅有t天时间收集珠宝,问最多能收集多少珠宝?

    思路:

      其实就是类似一个滑动窗口在收集一个序列上的权值。首先两个人可以同时往两边散开,直到极限距离dis(这样省时),然后他们可能往左/右走,也可能往左走一会儿再往右走,也可能往右走一会儿再往左走。可以看出其实这些考虑都是对称的,那么我们主要考虑1边就行了。可以尝试枚举往左边走k天,其他t-k天往右走(利用前缀和)。注意有可能dis是个奇数的,那么在t充足的情况下,应该两边扩展到dis-1就停下呢,还是往左/右一点呢?还得靠枚举,左边试一下,右边试一下。dis也可能比t还大,那么最多也就是同时往两边扩展t天。

      情况不算多,但是写起来还是得很小心的。还有,数据必须用longlong了。对称情况只需要反转一下序列,改变一下起点s。时间复杂度O(n)。

     1 //#include <bits/stdc++.h>
     2 #include <iostream>
     3 #include <cstdio>
     4 #include <cstring>
     5 #include <cmath>
     6 #include <map>
     7 #include <algorithm>
     8 #include <vector>
     9 #include <iostream>
    10 #define pii pair<int,int>
    11 #define INF 0x3f3f3f3f
    12 #define LL  long long
    13 using namespace std;
    14 const int N=100010;
    15 const double PI  = acos(-1.0);
    16 LL w[N], sum[N];
    17 int n, dis, s;
    18 LL get_ans(int p1,int p2,int t)
    19 {
    20     LL big=sum[p2]-sum[p1-1];
    21     LL ans=big;
    22     for(int k=0; k<p1&&t>=k; k++)   //枚举给左边k天,其他给右边
    23     {
    24         LL left=sum[p1-1]-sum[p1-k-1], right=0;
    25         int r=t-2*k;                    //若大于0,则可继续往右走
    26         if( r>0 )   right=sum[min(n,p2+r)]-sum[p2];    //右边还能获得珠宝
    27         ans=max(ans, big+left+right);
    28     }
    29     return ans;
    30 }
    31 
    32 
    33 LL cal(int t)    //初始定点p1,p2必须拉到最长
    34 {
    35     int p1=max(1, s-min(dis/2,t));
    36     int p2=min(n, s+min(dis/2,t));
    37     LL ans=0;
    38     t-=dis/2;
    39     if(dis%2==1)   //奇数
    40     {
    41         if( t<1 || p1==1&&p2==n )   return get_ans(p1,p2, t); //t已无剩
    42         if( p1>1 )  ans=max(ans, get_ans(p1-1,p2, t-1));    //左坑
    43         if( p2<n )  ans=max(ans, get_ans(p1,p2+1, t-1));    //右坑
    44     }
    45     else    //偶数,不需要占坑
    46     {
    47         ans=max(ans, get_ans(p1,p2, t));
    48     }
    49     return ans;
    50 }
    51 
    52 
    53 int main()
    54 {
    55     freopen("input.txt", "r", stdin);
    56     int t;LL ans;
    57     while(~scanf("%d%d",&n,&s))
    58     {
    59         memset(sum, 0, sizeof(sum));
    60         for(int i=1; i<=n; i++)
    61         {
    62             scanf("%d",&w[i]);
    63             sum[i]+=sum[i-1]+w[i];
    64         }
    65         scanf("%d%d",&dis,&t);    //dis是两人的距离上限,t是所有的时间
    66         ans=cal(t);
    67 
    68         reverse(w+1,w+n+1);     //反过来继续求。
    69         memset(sum, 0, sizeof(sum));
    70         for(int i=1; i<=n; i++)    sum[i]=sum[i-1]+w[i];
    71         s=n+1-s;
    72         ans=max(ans, cal(t));
    73         cout<<ans<<endl;
    74     }
    75     return 0;
    76 }
    AC代码
  • 相关阅读:
    WordPress WooCommerce ‘hide-wc-extensions-message’参数跨站脚本漏洞
    WordPress WP-Realty插件‘listing_id’参数SQL注入漏洞
    WordPress Videowall插件‘page_id’参数跨站脚本漏洞
    MySQL备忘点(上)
    Print工具类
    用于图片缩放的工具类
    重载、重写、方法相同
    Try-Catch-Finally代码块中的return
    Fltiss项目的架构、包名的定义和类的划分
    优化版快速排序
  • 原文地址:https://www.cnblogs.com/xcw0754/p/4833963.html
Copyright © 2020-2023  润新知