信息学宁波市竞赛2017 水题我爆炸系列

nb2017初中组题解。估计很多人满分吧,反正我没有。一等无望。
首先说一句:代码的失误有巨大影响。
就比如第四题,现在想起来,我贪心考虑太简单了,炸掉。
???这么水的题目????竟然错了?????


T 1:
题意:给出x和y,以及k组操作,让你求出最小几次操作之后x=y.
绝对乱搞过吧。样例很好,指出了几点:
1.x<0或y<0时,负数要变成0.
2.当k组操作之后,x不等于y,输出-1.
3.操作的次数要最小。

T 2:
题意:给出n,t,x。给出n个点,每个点坐标a[I],保证a[]是严格递增的。你可以安放警察,每个警察能工作长度为t,对每个a[I]至少要有x个警察正在管理该坐标。求出管住所有a[i]的最少安排的总警察数目。如果永远无法满足,输出-1.
安放警察有一些要求:每个时刻只能在一个位置放一个警察;放置后警察延时1个单位工作。
比如n=3,t=3,x=3,a={2,3,4}。即每个警察管理长度为t=3,每个a[i]需要x=3个警察来管理。
我们可以在-1,0,1三个坐标先放3个警察,他们分别可以管理:
(0,2)(1,3)(2,4).a[1]=2满足了有3个警察;然后a[2]=3,3位置只有2个警察,所以添加一个,在2坐标放1个,可以管理(3,5)这样就满足了a[2],同理a[3]=4也需要1个新警察。所以共5个。
分析:当t<x的时候,直接输出-1.原因不赘述。
然后来考虑有解的情况。可以看到,我们具备一个最最基本的贪心思想:对于一个警察的安放位置,在允许的范围内,肯定越靠后越好了。这样的话,可以尽量大地利用这个警察。
所以我们得到了一个思路:对于a[I],判断一下已经覆盖他的警察个数,然后剩余不够的个数就从a[I]-1开始,往前一个个安放。
具体的操作步骤可以看作:设置一个辅助数组W[],存放可用警察的最大延伸位置。然后对于a[I],找到t,使得W[t]>=a[I],然后将t~len(W)的警察取出,不足的警察放入W[]的尾部。这样可以保证W[]始终严格升序,而且n=10000,是可以A的。
PS:优化:对于a[I]和a[I-1](I>1),若a[I]-a[I-1]>t,直接ans+x.

T 3:
题意:给出n和t,以及n个数a[1..n],要求找到最短的长度s,使得存在Q,a[Q]+a[Q+1]+..+a[Q+s-1]>=t。n<=1000000.如果找不到输出-1.
分析:很经典的问题,可以看“羊羊吃草”这道题,是一样的,可以用一个队列来维护最小值。本人打了二分,原理都是一样的。
二分的正确性:如果答案r成立,那么比r大的长度肯定都成立。故可以二分。
-1的情况:显然,当sum(a[1..n])<t的时候,就输出-1.不然必定存在一个解。

T 4:
题意:给出n和长度为n的序列a[1..n],以及一个标准t。n<=1000000。你可以将任意的a[j]都乘以2,当然可以都不乘2.要求找出最长的一个序列x[],长度为m(m未给出),这个序列满足:
1.x[1..m]>=t.
2.x[I]>=x[I-1](I>1)。
比如n=5,t=3.a={1,4,1,4,3}
最长的序列x={4,4,6}
即a[5]*2,然后取出a[2],a[4],a[5],可以得到这个序列。由于1*2=2<3,所以1无论如何都无法放入任意长度x[]中
分析:如果说去掉题目中“可以把任意的a[j]都乘以2”这个条件去掉,题目就变成了:剔除一些a[k](a[k]*2<t),把a[r](a[r]<t<=a[r]*2)以a[r]*2的形式放入剩下的序列,求剩下序列的LIS。(LIS指最长不下降子序列)
首先我们看到,剔除的过程肯定是可以保留的,也就是说,像"1"这种元素,乘了2还是达不到t,我要你有何用??看上面那个样例,取出来的话,x={4,4,3},直接求LIS长度只有2,但是我们一眼就能看出,把3乘个2,答案会更优。
这里我们如果加个贪心:如果a[I]<a[I-1]而且a[I]放入的时候还没有乘过2,那么就把a[I]乘2.然后再做整个序列的LIS.
为什么这种贪心是正确的呢?我们看到,假如说以i结尾的最长序列长度是f[I],那么改变a[I]后:
1.f[I-1]不变。
2.f[I]只可能增大或不变。
看似完美??看下面的样例(刚想起来)
x=4 9 4 6
LIS=3.

如果说我6乘过2,4没有,就会变成
x=4 9 8 6.
LIS=2.

对吧,炸了。所以贪心乘2的时候要贪对。气死,这样最后一题的得分就不确定了。具体的贪心要看A【i】的前后两项。
然后O(Nlog(N))就可以水过了。

综上:水题系列,但是不够仔细就是爆炸。亏我浪费了1h。。

还是仔细的高手最强。



最后第4题的代码附一下(应求
var n,m,i,ans,x,o:longint;
        a,b:array[0..2000005] of longint;
function tianyehh(x:longint):longint;
var mid,l,r:longint;
begin
  l:=1; r:=ans;
  while (l<=r) do
  begin
    mid:=(l+r)>>1;
    if (b[mid]<=x)and(b[mid+1]>=x) then exit(mid+1);
    if b[mid]>x then r:=mid-1
        else l:=mid+1;
  end;
end;
begin
  readln(n,m);
  o:=0;
  for i:=1 to n do
  begin
        read(x);
        if ((x<<1)>=m) then begin inc(o); a[o]:=x<<1; end;
        if (x>=m) then begin inc(o); a[o]:=x; end;
  end;
  ans:=1; b[1]:=a[1];
  for i:=2 to o do
   if (a[i]>=b[ans]) then
   begin
        inc(ans);
        b[ans]:=a[i];
   end  else
   if (a[i]<b[1]) then
        b[1]:=a[i]
        else b[tianyehh(a[i])]:=a[i];
   writeln(ans);
end.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值