101104

距NOIP还有半个月,时间真的好紧张。。已经没有退路了,已经没有退路了,已经没有退路了!

相信自己!!!没有什么是不可能的!

一切  都在这半个月结束吧!

我来了!

为胜利而战!!

 

101104

 

题目

 

 

偷懒的小X(lazy)

【题目描述】

话说3008年的Orz教主节,全民狂欢,传递教主圣火,以致万人空巷,股票飞涨。真乃锣鼓喧天,鞭炮齐鸣,红旗招展,人山人海呐。可是小X为了准备NOIP3008,不得不待在家里好好Coding。小X希望早点结束当天的任务,加入圣火传递队伍中去。

在这个不亚于狂欢节的日子里,小X的老师却“公然违抗”休假法令,布置小X写一个小根堆,但是小X不会堆的操作,所以想了一个偷懒的办法:

堆是一棵完全二叉树,每个结点有一个权。小根堆的根的权最小,且根的两个子树也是一个堆。可以用一个数组a来记录一棵完全二叉树,a[1]为根结点,若结点a[j]不是根结点,那么它的父亲为a[j/2](取下整);若结点a[k]不是叶子结点,那么它的左儿子为a[2k],它的右儿子为a[2k+1]

他希望一组数据按一定顺序依次插入数组中(即第i个数为a[i]),最后得出来就已经是一个堆,即不需要任何交换操作,若有多种方法,输出字典序最大的一组,显得这个数据更乱。

 

【输入格式】

输入的第1行为一个正整数n,为插入的数字的个数。

2行包含n个正整数,为所有需要插入的数字,数字之间用空格隔开。

为了简化题目,数据保证n=2^k-1,即保证最后的堆是一棵满二叉树。

 

【输出格式】

输出包括1行,为插入的序列,数字之间用空格隔开,行末换行并没有空格。

 

【样例输入】

3

10 2 1

 

【样例输出】

1 10 2

 

【样例说明】

1 2 101 10 2都是满足要求的插入序列,但是1 10 2的字典序更大。

 

【数据规模】

  对于20%的数据,n7

对于30%的数据,n15

对于50%的数据,n1023

对于100%的数据,n65535,所有数字不超过10^8,且各不相同。

 


渡河(river)

【题目描述】

传说中教主乃世外高人,不屑于参加OI竞赛,于是云游四方,威风八面。只不过教主行踪不定,就像传说中的神兽一样可遇而不可求。小L和小H为了求得教主签名的Orz教主T-Shirt,打算碰碰运气展开了冒险。在冒险中,他们不幸被突来的洪水冲到了一个神秘丛林中,他们想尽快逃出这个地方。小L找到了一张看似为曾经的冒险者遗弃的地图,但经过探查,地图所示的确实是这片丛林。小L从地图上看到,有众多河流穿过这片丛林,等到他接近一条最近的河流时,发现水流较急,且河水很深,小H不擅长游泳,所以他们决定利用丛林中的树木做一只竹筏渡河。

虽然竹筏做好后可以在这一条河所连通的水域任意行进,但是竹筏在上岸后必须抛弃,若想再次渡河必须再做一次竹筏,但这毕竟是十分辛苦的,他们希望做竹筏也就是渡河的次数尽量少,就求助于你。

地图上的陆地和河流可以抽象冲一个n*n由数字01组成的矩阵,其中0代表陆地,1代表河流。无论在陆地上还还是河流上,他们都可以向相邻8格(边相邻或角相邻)移动,但是若要从陆地进入河流(也就是从01),则必须制作竹筏。若到达地图边界则顺利逃脱。但是小T和小K有可能迷路,所以会多次询问你,对于每次询问,只要输出到达地图边界需要的最少渡河次数即可,保证每次询问都是指向陆地。

L和小H翻到地图的反面,赫然发现六个大字:“教主到此一游”!两人无法抑制自己激动的心情,将这张地图珍藏起来。据说后来这张图成为无价之宝。

 

【输入格式】

1行包括2个正整数NK,分别描述了地图的长宽以及询问的次数。

下面N行,每行N个数字0或者1,数字之间没有空格,描述了这张地图。

接下来K行,每行2个正整数xiyi,询问在第xi行第yi列最少需要渡河几次。

 

【输出格式】

  输出仅包括1行,按输入顺序每行对于一个询问输出最少需要渡河的次数,数字间用空格隔开,行末换行并没有空格。

 

【样例输入】

  9 3

000000000

011111110

010101010

011000110

010000010

010111010

010101010

011111110

000000000

1 3

3 3

4 6

 

【样例输出】

0 1 1

 

【样例说明】

1次询问由于已经处于边界所以答案为0

2次询问不断向左或向上走都只要渡河1次。

3次询问不断向四个方向中的一个方向走同样只需要1次渡河。

 

【数据规模】

对于20%的数据,有n10

对于40%的数据,有n100k10

对于60%的数据,有n1000k100

对于100%的数据,有n1000k40000

 


菱形内的计数(diamond)

【问题描述】

教主上电视了!这个消息绝对是一个爆炸性的新闻。一经传开,大街上瞬间就没人了(都回家看电视去了),商店打烊,工厂停业。大家都把电视机的音量开到最大,教主的声音回响在大街小巷。

L给小X慌乱地打开自己家的电视机,发现所有频道都播放的是教主的采访节目(-_-bbb)。只见电视屏幕上的教主笑意吟吟,给大家出了一道难题:

一个边长为n的大菱形被均匀地划分成了n*n个边长为1的小菱形组成的网格,但是网格中部分边被抹去了,小L想知道,大菱形内有多少个平行四边形,这些平行四边形内不存在边。

教主说,如果谁写出了程序,移动用户请将程序发送到xxxx,联通用户请将程序发送到xxxx……如果答对这个题,将有机会参加抽奖,大奖将是教主签名的Orz教主T-Shirt一件!这个奖品太具有诱惑力了。于是你需要编一个程序完成这么一道题。

 

【输入格式】

输入的第1行为一个正整数n,为大菱形的边长。

以下2n行,每行2n个字符,字符为空格,“/”,“/”中的一个。

n行,第i行中居中有2i个字符,这2i个字符中位置为奇数的字符只可能为“/”或者空格,位置为偶数的字符只可能为“/”或空格,若为空格表示这样一条边不存在,其余字符均为空格,描述了大菱形的上半部分。

n行,第i行居中有有2(n-i+1)个字符,与上半部分类似地描述了菱形的下半部分

输入文件保证大菱形的轮廓上没有边被抹去。

 

【输出格式】

输出仅包括一个整数,为满足要求的平行四边形个数。

 

【样例输入】

3

  //

 

/ // /

///  /

 / //

  //

 

【样例输出】

  3

 

【数据规模】

对于20%的数据,n10

对于40%的数据,n60

对于60%的数据,n200

对于100%的数据,n888

 


电缆建设(cable)

【问题描述】

教主上电视了,但是蔚蓝城郊区沿河的村庄却因电缆线路老化而在直播的时候停电,这让市长SP先生相当的愤怒,他决定重修所有电缆,并改日播放录像,杜绝此类情况再次发生。

河流两旁各有nm个村庄,每个村庄可以用二维坐标表示,其中河流一旁的村庄横坐标均为x1,河流另一旁的村庄横坐标均为x2。由于地势十分开阔,任意两个村庄可以沿坐标系直线修建一条电缆连接,长度即为两村庄的距离。要修建若干条电缆,使得任意两个村庄都可以通过若干个有电缆连接的村庄相连。

因为修建的经费与长度成正比,SP市长当然希望所花的钱越少越好,所以他希望你来帮助他设计一套方案,使得电缆总长度最小,并告诉所需要的电缆总长度。

 

【输入格式】

输入的第1行为四个正整数,nmx1x2,表示河流两旁的村庄数以及横坐标。

2行有n个正整数y1[1], y1[2]... y1[n],描述了横坐标为x1的村庄的纵坐标。第1个整数为纵坐标最小的那个村庄的纵坐标,从第2个整数开始,第i个整数代表当前村庄与前一个村庄的纵坐标差,即y[i]-y[i-1]

3行有m个正整数y2[1], y2[2]... y2[n],用同样的方法描述了横坐标为x2的村庄的纵坐标。

 

【输出格式】

  输出仅包括一个实数,为最小的总长度,答案保留两位小数。

 

【样例输入】

2 3 1 3

1 2

2 2 1

 

【样例输出】

  7.24

 

【样例解释】

  按如下方案建设电缆,括号内代表村庄的坐标,“-”代表有电缆连接。

(1,1)-(1,3)

(1,3)-(3,4)

(3,4)-(3,2)

(3,4)-(3,5)

 

【数据规模】

对于20%的数据,nm10

对于40%的数据,nm1000

对于70%的数据,nm100000

对于100%的数据,nm600000,所有村庄纵坐标不超过10^8x1x22000,输入文件不超过4M

 

 

 

 

解题报告

 

 

前言:

4题与上次一样均为原创,若有雷同,纯属我太菜没见过。

 

偷懒的小X(lazy)

本题要求的是一个字典序最大的堆。首先将所有数字排序,根据堆的定义,堆的根权最小,左右子树都是一个堆,所以将最小的数放在根,接着因为在数组中左子树根排在右子树根前,所以将剩下的数大的一半分给左子树的堆,小的一半分给右子树的堆,利用分治递归解决即可。

 

渡河(river)

本题若只有1个询问,由于在同一个数字内走动是自由的,利用Flood Fill,每次寻找当前渡河次数能到的范围,直到范围到达边界为止位置。

40%-60%的数据可以这样解决。

同理,从外到内Flood Fill也是可以的,由于是8连的连通块,所以一个不在边界上的连通块必然被另一个连通块包围,而每个连通块所需步数一样,题目也可以理解为进入尽量少的连通块。所以顺序扫描i, jFlood Fill所有没被填充过的连通块,由于询问不会在1上,进入这个连通块所需要的次数即包围它的连通块(必然已经被Flood Fill过)的次数(若这个连通块为1)或包围它的连通块的次数+1(若这个连通块为0)。

 

菱形内的计数(diamond)

首先将在读入时将菱形转成正方形,统计矩形的个数。

(n+1)*(n+1)个格点,用d[i][j]表示第i行第j列的格点到第1行第j列的格点之间有多少条竖线,f[i][j]表示第i行第j条横线(被抹去的也算)的距离上一条没被抹去横线的位置。

接着扫描i,jh为矩形的高,初值为-1。若第i行第j根横线没被抹去,且d[i][j]-d[i-f[i][j]]=f[i][j]即当前横线到上一根横线的左边有封闭的竖线,那么表示这可能是一个矩形的开始,此时矩形的高h赋为f[i][j]。若h>-1,且h[i][j]-h[i-h][j]>0即当前扫描到的段左边有若干条竖线(矩形内不为空);或f[i][j]<>h(矩形内不为空或不是矩形);或当前扫描到的横线被抹去,h赋为-1。若h>-1d[i][j+1]-d[i-h][j+1]=h,即横线右边线段有封闭的竖线,那么答案+1

 

A

B

C

D

电缆建设(cable)

本题即为平面图上的MST,特殊的是只有两排点。

普通的MST算法可以拿到40%的分数。但是由于图的特殊性,有以下推论:

  1MST中不会有线段相交,ADBC相交,无论AB有不经过ADBC路径相连还是CD有不经过ADBC路径,改连ACBD会使得生成树权和更小。

B

C

A

2、若有点A(x1,y1),B(x1,y2),C(x2,y3),且y1<y2<y3,那么边AC不可能在MST里。由于线段不交叉,BC上方的点不可能与下方的点有连接,所以在MST中,不考虑BC以下点的情况下,BC要么同时属于MST中的一棵树中(B C连通),要么分别属于两棵树(B C不连通)。在BC连通的情况下,连接BA与连接AC同样将树扩展到了A及以上,由于ABC为钝角三角形,AB<AC,所以连BA只会使结果更优。在BC不连通的情况下,单连AC会使树不连通,再连ABBC等价于连ABBC,但是权更大。

所以这种情况AC是不可能连边。

这样就可以构出一张边数最多为2(m+n)条的新图,使用Kruskal时间复杂度O((n+m)log(n+m))期望得分为70-100

但是这题时间复杂度最低,写起来最简单的方法是DP

f[i][j][0..1]表示左边第i个点(下简称为点i)与右边第j个点(下简称为点j)以下的点已经处理完毕(即不可能再有边连到这2个点以下的点),且点i与点j连通/不连通。f[i][j]可以从f[i-1][j]f[i][j-1]转移,f[i][j]f[i-1][j]转移方程为(从f[i][j-1]基本相同,a为左边点坐标,dist(i,j)为点i到点j的距离):

f[i][j][1]=min(f[i-1][j][1]+a[i]-a[i-1],

               f[i-1][j][1]+dist(i,j),

               f[i-1][j][0]+a[i]-a[i-1]+dist(i,j))

f[i][j][0]=min(f[i-1][j][1],

               f[i-1][j][0]+a[i]-a[i-1])

由于新图中只有i, j相邻才可能连边,所以维护i, j相邻,这样最多只会用到n+m个状态。状态中ij都可以滚动,时间复杂度O(n+m)

 

 

一测  110

 

 

第一题不难  一次AC

  由小到大排序   然后用递归求解

 

 

const
  maxn=65535;
var
  n,i:longint;
  a,b:array[1..maxn] of longint;
procedure init;
var
  i:longint;
begin
  assign(input,'lazy.in');
  reset(input);
  assign(output,'lazy.out');
  rewrite(output);
  readln(n);
  for i:=1 to n do read(a[i]);
end;
procedure qsort(l,r:longint);
var
  i,j,x,t:longint;
begin
  i:=l;j:=r;
  x:=a[(i+j) shr 1];
  repeat
    while a[i]<x do inc(i);
    while a[j]>x do dec(j);
    if i<=j then
    begin
      t:=a[i];
      a[i]:=a[j];
      a[j]:=t;
      inc(i);dec(j);
    end;
  until i>j;
  if i<r then qsort(i,r);
  if j>l then qsort(l,j);
end;
procedure f(k:longint);
begin
  b[k]:=a[i];
  inc(i);
  if 2*k>n then exit;
  f(2*k+1);
  f(2*k);
end;
procedure main;
begin
  qsort(1,n);
  i:=1;
  f(1);
  for i:=1 to n-1 do write(b[i],' ');
  writeln(b[n]);
end;
procedure outit;
begin
  close(input);
  close(output);
end;
begin
  init;
  main;
  outit;
end.

 

关键!!!------

f(2*k+1);
  f(2*k);
这两句顺序不能颠倒!

因为要输出字典序大的 

所以对于一个根的两个子节点  要让左边大于右边

  所以要先算 f(2*k+1);
   再算 f(2*k);

不然就洗白了。。。

 

这里补充一个概念------“小根堆”:  简单的说就是根节点比子节点小的堆

 

堆很牛B啊。。。

 

 

二三题仍在奋斗中

 

二题主要思想是染色  从外向里

三题牵扯到数学方法。。

 

四题

 

第一次做的时候  期望得分40分,但是只拿了10分,有两个地方没考虑到位

 

贴下40分代码:


const
  maxn=1000;
type
  arr=array[0..2*maxn+1] of record
    x:longint;
    y:int64;
  end;
var
  p,n,m,x1,x2:longint;
  a:arr;
  cost:array[0..2*maxn+1,0..2*maxn+1] of double;
  total:double;
procedure init;
var
  i,t,j:longint;
  k:int64;
begin
  assign(input,'cable.in');
  reset(input);
  assign(output,'cable.out');
  rewrite(output);
  fillchar(a,sizeof(a),0);
  readln(n,m,x1,x2);
  for i:=1 to n do
  begin
    read(k);
    a[i].x:=x1;
    a[i].y:=a[i-1].y+k;
  end;
  t:=a[n].y;
  a[n].y:=0;
  for i:=n+1 to n+m do
  begin
    read(k);
    a[i].x:=x2;
    a[i].y:=a[i-1].y+k;
  end;
  a[n].y:=t;
  p:=n+m;
  for i:=1 to p do
    for j:=1 to p do
      cost[i,j]:=sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));
end;
procedure prim;
var
  pre:array[0..2*maxn] of longint;
  dist:array[0..2*maxn] of double;
  i,j,k:longint;
  min:double;
begin
  for i:=1 to p do
  begin
    dist[i]:=cost[1,i];
    pre[i]:=1;
  end;
  for i:=1 to p-1 do
  begin
    min:=maxlongint;
    for j:=1 to p do
    if (dist[j]<min) and (dist[j]<>0) then
    begin
      min:=dist[j];
      k:=j;
    end;
    total:=total+min;
    dist[k]:=0;
    for j:=1 to p do
      if cost[k,j]<dist[j] then
      begin
        dist[j]:=cost[k,j];
        pre[j]:=k;
      end;
  end;
end;
procedure main;
begin
  prim;
  writeln(total:0:2);
end;
procedure outit;
begin
  close(input);
  close(output);
end;
begin
  init;
  main;
  outit;
end.

 

一测过了一组 两个问题:

 

  一

     “所有村庄纵坐标不超过10^8”

    题目这句真是精彩。。。。

    10的8次方。。。

    Y得用INT64;

    所有实数型变量得用DOUBLE;

 二

   procedure prim;
var
  pre:array[0..2*maxn] of longint;
  dist:array[0..2*maxn] of double;

这里的数组下标越界。。

开始开的是0..maxn。。。

我是把N和M加一起来算的  所以要开到2倍

所以要多总结。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值