NOIP2011 观光公交 解题报告(贪心(贪心一次更新一次))

6 篇文章 0 订阅
4 篇文章 0 订阅

在线评测:

http://codevs.cn/problem/1139/


整体思路:

我们先记录一下每个站点的最晚到达的乘客的到达时间,然后我们也可以记录每个站点到下一个站点的路程上车上的人数,并将其维护成一个前缀和,同时我们初始化出到达每个景点的时间,

for (int i = 2;i <= n;i++)
	{
		dd[i] = max(zw[i - 1],dd[i - 1]) + t[i - 1];
	}

并求出乘客的总的时间,

for (int i = 1;i <= m;i++)
		ans += dd[zd[i]] - cf[i];

然后我们可以贪心至多k次,贪减少时间最多的,(选择一个点释放氮气,使其使乘客减少的时间最多),并更新相关数组,到达每个点的时间,两点间的距离,贪心到氮气用光,或者每条路径都无法缩短为止。

失误之处:

维护两点间距离时,傻傻的一直修改的到达时间,,(这样还过了样例和一个点,数据水,,)

体会心得:

明确每个数组的定义,不要搞错,也不要随便糊弄过去,


AC代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using  namespace  std;
int  n,m,k,t[11000],cf[11000],qd[11000],zd[11000];
int  zw[11000],rs[11000],dd[11000],ans,g[11000];
void  sread()
{
     scanf ( "%d%d%d" ,&n,&m,&k);
     for  ( int  i = 1; i < n;i++)
         scanf ( "%d" ,&t[i]);
     for  ( int  i = 1;i <= m;i++)
     {
         scanf ( "%d%d%d" ,&cf[i],&qd[i],&zd[i]);
     }
}
void  init()
{
     for  ( int  i = 1;i <= m;i++)
     {
         zw[qd[i]] =  max(zw[qd[i]],cf[i]);
         rs[zd[i]]++;
     }
     for  ( int  i = 1;i <= n;i++)
         rs[i] = rs[i - 1] + rs[i];
     for  ( int  i = 2;i <= n;i++)
     {
         dd[i] = max(zw[i - 1],dd[i - 1]) + t[i - 1];
     }
     for  ( int  i = 1;i <= m;i++)
         ans += dd[zd[i]] - cf[i];
 
}
void  swork()
{
     while (k)
     {
         g[n] = n;
         g[n - 1] = n;
         for  ( int  i = n - 2;i >= 1;i--)
         {
             if  (dd[i + 1] <= zw[i + 1]) g[i] = i + 1; else  g[i] = g[i + 1];
         }
         k--;
         int  maxn = 0,maxw = 0;
         for  ( int  i = 1;i < n;i++)
         {
             if  (rs[g[i]] - rs[i] > maxn && t[i] > 0)
             {
                 maxn = rs[g[i]] - rs[i];
                 maxw = i;
            
         }
//      printf(" maxn = %d\n",maxn);
         if  (!maxn)  break ;
         t[maxw]--;
         ans -= maxn;
//      printf("jian %d\n",maxn);
         for  ( int  i = maxw + 1;i <= n;i++)
             dd[i] = max(dd[i - 1],zw[i - 1]) + t[i - 1];
     }
     printf ( "%d\n" ,ans);
}
int  main()
{
     sread(); 
     init();
     swork();
     return  0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 一元三次方程是指形如ax^3+bx^2+cx+d=的方程,其中a、b、c、d都是已知常数,x是未知数。 求解一元三次方程的一般步骤如下: 1. 将方程化为标准形式,即将x^3系数化为1,即可得到x^3+px^2+qx+r=的形式。 2. 通过代数运算,将方程化为一个二次方程和一个一次方程的组合形式,即x^3+px^2+qx+r=(x-a)(x^2+bx+c)的形式。 3. 解出二次方程x^2+bx+c=的两个根,即可得到三次方程的三个根,分别为a和二次方程的两个根。 求解一元三次方程的具体方法有很多,可以使用牛顿迭代法、三分法、高斯消元法等。在NOI竞赛中,一般使用高斯消元法来求解一元三次方程。 ### 回答2: 一元三次方程是指形如ax³+bx²+cx+d=0的方程,其中a、b、c、d都是已知系数,x是未知数。这是一个高阶多项式方程,求解方法也比较复杂。下面介绍一种较为常用的三次方程求解方法——套用“因式分解法”: 1. 将三次方程写成“因式分解”的形式,即(ax+b)(cx²+ex+f)=0,其中a、b、c、e、f都是已知系数,x是未知数。 2. 将第二个括号展开,得到cx³+(e+a)c²x+(f+ae+b)c+be=0。 3. 令y=cx,即方程变成了一个一元二次方程:y²+(e+a)y+(f+ae+b)c/be=0。 4. 解出y,再回代得到x的值。 需要注意的是,如果三次方程有重根或虚根,以上方法不适用,需要采用其他的求解方式。除此之外,还可以利用“维达定理”或牛顿迭代法等算法进行求解。 总之,求解一元三次方程需要掌握多种方法,根据具体情况选择合适的方法进行求解。在解题的过程中,要注意化简、观察特征、分析符号及系数等问题,同时也需要熟悉求根公式和基本的代数计算方法,才能顺利解决问题。 ### 回答3: 一元三次方程是指形如ax^3+bx^2+cx+d=0的方程,其中a、b、c、d为系数,x为未知数。解一元三次方程是高中数学中的一项重要内容,也是竞赛中常出现的题型。 解一元三次方程的方法有很多种,其中比较常用的有以下几种: 1.牛顿迭代法。该方法通常用于求解非线性方程,使用重复求解近似解的方法逼近准确解。但需要注意的是,该方法需要计算一定的导数,因此不太方便手工计算。 2.公式法。一元三次方程也有和一元二次方程一样的求根公式,但通常需要做一定的化简。比如,可以利用单项式恒等变形把一元三次方程化为一元二次方程,然后使用公式求解。 3.因式分解法。有些一元三次方程可以通过因式分解得到解,比如x^3-8=0,可以分解为(x-2)(x^2+2x+4)=0,从而得到三个解x=2、x=-1+i√3、x=-1-i√3。 4.牛顿-拉弗森法。该方法也是一种迭代方法,通常用于求根问题。但由于需要计算导数,因此不太适合手工计算。 总之,解一元三次方程需要根据具体情况选择合适的方法,并且需要注意精度问题,避免出现误差过大的情况。在竞赛中,还需要注意时间限制,尽量选择快速有效的方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值