NOIP 2011 提高组复赛真题及题解(day1 day2) Pascal语言

题目描述

为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯。一共有n 张地毯,编号从1 到n。现在将这些地毯按照编号从小到大的顺序平行于坐标轴先后铺设,后铺的地毯覆盖在前面已经铺好的地毯之上。地毯铺设完成后,组织者想知道覆盖地面某个点的最上面的那张地毯的编号。注意:在矩形地毯边界和四个顶点上的点也算被地毯覆盖。

输入

输入共 n+2 行。
第一行,一个整数 n,表示总共有n 张地毯。
接下来的 n 行中,第i+1 行表示编号i 的地毯的信息,包含四个正整数a,b,g,k,每两个整数之间用一个空格隔开,分别表示铺设地毯的左下角的坐标(a,b)以及地毯在x轴和y 轴方向的长度。
第 n+2 行包含两个正整数x 和y,表示所求的地面的点的坐标(x,y)。

输出

输出共 1 行,一个整数,表示所求的地毯的编号;若此处没有被地毯覆盖则输出-1。

样例输入

样例1:
3
1 0 2 3
0 2 3 3
2 1 3 3
2 2

样例2:
3
1 0 2 3
0 2 3 3
2 1 3 3
4 5

样例输出

样例1:
3

样例2:
-1

提示

对于 30%的数据,有n≤2;
对于 50%的数据,0≤a, b, g, k≤100;
对于 100%的数据,有0≤n≤10,000,0≤a, b, g, k≤100,000。

铺地毯解题报告

carpet为一个简单的模拟题,只需把每一个地毯所覆盖的长和宽计算出来,然后直接用最后一个点的坐标模拟找出最后一个覆盖点即可!

【参考程序】

program carpetl;
type aa=record
        a,b,g,k:longint;
       end;
var a:array[1..10000] of aa;
   n,i,j,k,x1,y1,total:longint;
begin
assign(input,'carpet.in');reset(input);
assign(output,'carpet.out');rewrite(output);
  readln(n);
for i:=1 to n do
    readln(a[i].a,a[i].b,a[i].g,a[i].k);
readln(x1,y1);
for i:=1 to n do
    if (x1>=a[i].a)and(x1<=a[i].a+a[i].g)and(y1>=a[i].b)and(y1<=a[i].b+a[i].k) then
total:=I;
  if total=0 then writeln(-1)
          else writeln(total);
  close(input);close(output);
end.

    选择客栈解题报告

此题可用爆搜去解决!

如果有三重循环有望的60!

可以换一个思路,开一个c数组来记录同一个色调的旅馆的个数,c[j,i]表示j色调的旅馆数为I,然后可以用一个色调的总个数来减去到这一个小于最高消费的中间的个数!最后把这些总个数累加用total记录起来就OK了!

实际上就是找色调相同的以及最高消费的费用!

算法的复杂度为O(n*k);时间复杂度有点高!

不过可以再给定时间内全过测试点!

【参考程序】

Program hotel;
type aa=record
         c,m:longint;
        end;
var a:array[1..200000] of aa;
    c:array[0..50,0..200000] of longint;
    n,i,j,m,k,p:longint;
    total:int64;
    f:boolean;
begin
  assign(input,'hotel.in');reset(input);
  assign(output,'hotel.out');rewrite(output);
   readln(n,k,p);
    for i:=1 to n do
    begin
     readln(a[i].c,a[i].m);
     for j:=0 to k do
       if a[i].c=j then c[j,i]:=c[j,i-1]+1
          else c[j,i]:=c[j,i-1];
   end;
    for i:=1 to n do
      begin
       f:=false;
       if a[i].m<=p then f:=true;
      for j:=i+1 to n do
       begin
        if f then begin
                  total:=total+(c[a[i].c,n]-c[a[i].c,j-1]);
                  break;
                 end;
       if a[j].m<=p then
                    begin
                      total:=total+(c[a[i].c,n]-c[a[i].c,j-1]);
                      f:=true;
                      break;
                    end;
       end;
       end;
    writeln(total);
  close(input);close(output);
end.

     mayan游戏解题报告

     这道题目时间限制3s,明显就是搜索的题目,但是如何去搜索,是一个值得想的问题

     这道题目主要考察的就是编程的能力……

【参考程序】

type love=record
            x,y,z:longint;
           end;
var a,b:array[0..7,0..9] of integer;
    n,i,j,k,t,c:longint;
    zt:array[1..8] of love;
procedure print1;
var i:longint;
begin
  if t=0 then writeln(-1)
    else
    for i:=1 to t do
     writeln(zt[i].x-1,' ',zt[i].y-1,' ',zt[i].z);
   halt;
end;

procedure down;
var i,j,y1:longint;
begin
  for j:=2 to 7 do
   for i:=1 to 5 do
    if (a[i,j]<>0)and(a[i,j-1]=0) then
     begin
      y1:=j;
      repeat
       dec(y1);
      until (y1=1) or (a[i,y1]<>0);
     if a[i,y1]<>0 then a[i,y1+1]:=a[i,j]
       else a[i,y1]:=a[i,j];
      a[i,j]:=0;
     end;
end;

procedure swap(x1,y1,x2,y2:integer);
var xx:longint;
begin
  xx:=a[x1,y1]; a[x1,y1]:=a[x2,y2]; a[x2,y2]:=xx;
end;

function check:boolean;
var i,j,m:integer;
    v:array[0..7,0..9] of boolean;
    have:boolean;
begin
  fillchar(v,sizeof(v),false);
   have:=false;
  down;
  for i:=1 to 5 do
   for j:=1 to 7 do
    if a[i,j]<>0 then
     begin
      if (a[i,j]=a[i+1,j])and(a[i,j]=a[i+2,j]) then
       begin
        v[i,j]:=true; v[i+1,j]:=true; v[i+2,j]:=true; have:=true;
       end;
      if (a[i,j]=a[i,j+1])and(a[i,j]=a[i,j+2]) then
       begin
        v[i,j]:=true; v[i,j+1]:=true; v[i,j+2]:=true; have:=true;
       end;
     end;
    if have then
      begin
       for i:=1 to 5 do
        for j:=1 to 7 do
         if v[i,j] then a[i,j]:=0;
       m:=0;
       for i:=1 to 5 do
        for J:=1 to 7 do
         if a[i,j]<>0 then inc(m);
          if m=0 then print1;
      end;
     if have then begin down; exit(true); end;
   exit(false);
end;

procedure dfs;
var i,j,xx,yy:longint;
    aa:array[0..7,0..9] of integer;
begin
 if t>=n then exit;
  aa:=a;
  for i:=1 to 5 do
   for j:=1 to 7 do
    if a[i,j]<>0 then
     begin
      if b[i,j]+1=0 then continue;
      if i+1<=5 then
      begin
        swap(i,j,i+1,j);
        xx:=b[i,j]; yy:=b[i+1,j];
        inc(t);
        zt[t].x:=i; zt[t].y:=j; zt[t].z:=1;
        b[i,j]:=-1; b[i+1,j]:=1;
        while check do check;
        dfs;
        dec(t);
        b[i,j]:=xx; b[i+1,j]:=yy;
        a:=aa;
      end;
   if (a[i-1,j]<>0)or(i=1)or(b[i,j]=1) then continue
    else
     begin
      swap(i,j,i-1,j);
      inc(t);
      zt[t].x:=i; zt[t].y:=j; zt[t].z:=-1;
      xx:=b[i,j]; yy:=b[i-1,j];
      b[i,j]:=1;  b[i-1,j]:=-1;
      while check do check;
      dfs;
      b[i,j]:=xx; b[i-1,j]:=yy;
      dec(t);
      a:=aa;
     end;
   end;
end;

begin
  read(n);
  for i:=1 to 5 do
   begin
    k:=0;
    repeat
     read(c);
     if c<>0 then
       begin inc(k); a[i,k]:=c; end;
    until c=0;
   end;
   dfs;
   print1;
end.

题目描述
给定一个多项式(ax + by)k,请求出多项式展开后 x^ny^m 项的系数。

输入格式
共一行,包含 5 个整数,分别为 a,b,k,n,m,每两个整数之间用一个空格隔开。

输出格式
输出共 1 行,包含一个整数,表示所求的系数,这个系数可能很大,输出对 10007 取模后的结果。

样例数据 1
输入

1 1 3 1 2
输出

3
备注
【数据范围】
对于 30% 的数据,有0≤k≤10;
对于 50% 的数据,有a=1,b=1;
对于 100% 的数据,有0≤k≤1,000,0≤n,m≤k,且 n+m=k,0≤a,b≤1,000,000。

计算系数解题报告

 此题为一个有关数论的题!可以用递推+同余来解决!递推公式就是普通的杨辉三角的递推式

f[i,j]:=f[i-1,j]+f[i-1,j-1];

(ax+by)k展开后xnym的系数是有关a和b的一个公式!

即系数为an*bm*f[k+1,n+1];

在计算过程中应该用到同余来防止数超范围!

【参考程序】

var f:array[0..5000,0..1050] of longint;
    n,m,i,j,k,a,b,x,y:longint;
function chengfang(xx,yy:longint):longint;
var ii,jj:longint;
begin
  jj:=1;
  for ii:=1 to yy do
   jj:=(jj*xx) mod 10007;
  exit(jj mod 10007);
end;
begin
  assign(input,'factor.in');reset(input);
  assign(output,'factor.out');rewrite(output);
   readln(a,b,k,n,m);
  f[1,1]:=1;
  a:=a mod 10007;b:=b mod 10007;
  for i:=2 to k+1 do
    for j:=1 to i do
      f[i,j]:=(f[i-1,j]+f[i-1,j-1])mod 10007;
     x:=chengfang(a,n);
     y:=chengfang(b,m);
     x:=(x*y) mod 10007;
     x:=(x*f[k+1,n+1]) mod 10007;
   writeln(x);
  close(input);close(output);
end.

    聪明的质检员解题报告

 或许起初会感觉是动态规划!!!

但本题主要是考察二分法!

题目规则是这样的:找一个w ,让(大于等于w的值的矿产个数)*(大于等于w的矿产的总价值)与标准值的绝对值取得最小值;我们可以枚举每一个矿产的质量!这样可以拿到45分左右!而如果用到二分皆就可以在限定时间内全过测试点!

其实或许你是枚举的从最小质量到最大质量,但是那是不必要的!因为总是在w有此值是才会取得与最优解!

用一个total来记录每一个w值来检测是否为最优解,让后用sum和sumv数组来记录每一个w值所对应的与标准值s绝对值差值最小的,把每一个区间都计算出来!找一个w,其实就是二分质量!然后可以用

Total:=(sum[r[i]]-sum[l[i]-1])*(sumv[r[i]]-sumv[[i]-1])+total来累加total的值,最后找一个最小值就OK!了!

【参考程序】

Program qc;
type aa=record
          w,v:longint;
        end;
var sum,sumv:array[0..200000] of int64;
    a:array[1..200000] of aa;
    l,r,b:array[1..200000] of longint;
    s,total,min1,max,min,tt:int64;
    i,j,k,n,m,p,mid:longint;
procedure work(xx:longint);
var ii,jj:longint;
begin
  for ii:=1 to n do
   if a[ii].w>=xx then
    begin
     sum[ii]:=sum[ii-1]+1;
     sumv[ii]:=sumv[ii-1]+a[ii].v;
   end
  else begin
    sum[ii]:=sum[ii-1];
    sumv[ii]:=sumv[ii-1];
      end;
end;
procedure kuaipai(st,ed:longint);
var i,j,mm,mid:longint;
begin
  if st>=ed then exit;
  i:=st-1;j:=ed+1;
  mid:=b[(st+ed) div 2];
  while (i<j) do
   begin
    repeat inc(i) until b[i]>=mid;
    repeat dec(j) until b[j]<=mid;
    if i<j then
     begin
       mm:=b[i];
       b[i]:=b[j];
       b[j]:=mm;
     end;
   end;
  kuaipai(st,j);kuaipai(j+1,ed);
end;
begin
  assign(input,'qc.in');reset(input);
  assign(output,'qc.out');rewrite(output);
  readln(n,m,s);
  max:=-maxlongint;
  min:=maxlongint;
   for i:=1 to n do
   begin
     readln(a[i].w,a[i].v);
     if max<a[i].w then max:=a[i].w;
     if a[i].w<min then min:=a[i].w;
     b[i]:=a[i].w;
   end;
  for i:=1 to m do readln(l[i],r[i]);
  min1:=100000000000000;
    kuaipai(1,n);
  i:=1;j:=n+1;
  while (i<=j) do
   begin
    mid:=(i+j) div 2;
    work(b[mid]);
     total:=0;
    for k:=1 to m do
     begin
      tt:=(sum[r[k]]-sum[l[k]-1])*(sumv[r[k]]-sumv[l[k]-1]);
      total:=total+tt;
     end;
    if abs(total-s)<min1 then min1:=abs(total-s);
    if total>s then i:=mid+1
      else j:=mid-1;
   end;
  writeln(min1);
 close(input);close(output);
end.

题目描述

风景迷人的小城 Y 市,拥有 n 个美丽的景点。由于慕名而来的游客越来越多,Y 市特意安排了一辆观光公交车,为游客提供更便捷的交通服务。观光公交车在第 0 分钟出现在 1 号景点,随后依次前往 2、3、4……n 号景点。从第 i 号景点开到第 i+1 号景点需要 Di 分钟。任意时刻,公交车只能往前开,或在景点处等待。

设共有 m 个游客,每位游客需要乘车 1 次从一个景点到达另一个景点,第 i 位游客在 Ti 分钟来到景点 Ai,希望乘车前往景点 Bi(Ai<Bi)。为了使所有乘客都能顺利到达目的地,公交车在每站都必须等待需要从该景点出发的所有乘客都上车后才能出发开往下一景点。假设乘客上下车不需要时间。

一个乘客的旅行时间,等于他到达目的地的时刻减去他来到出发地的时刻。因为只有一辆观光车,有时候还要停下来等其他乘客,乘客们纷纷抱怨旅行时间太长了。于是聪明的司机 ZZ 给公交车安装了 k 个氮气加速器,每使用一个加速器,可以使其中一个 Di 减 1。对于同一个 Di 可以重复使用加速器,但是必须保证使用后 Di 大于等于0。

那么 ZZ 该如何安排使用加速器,才能使所有乘客的旅行时间总和最小?

输入格式

第 1 行是 3 个整数 n, m, k,每两个整数之间用一个空格隔开。分别表示景点数、乘客数和氮气加速器个数。

第 2 行是 n-1 个整数,每两个整数之间用一个空格隔开,第 i 个数表示从第 i 个景点开往第 i+1 个景点所需要的时间,即 Di 。

第 3 行至 m+2 行每行 3 个整数 Ti, Ai, Bi,每两个整数之间用一个空格隔开。第 i+2 行表示第 i 位乘客来到出发景点的时,出发的景点编号和到达的景点编号。

输出格式

共一行,包含一个整数,表示最小的总旅行时间。

样例数据 1

输入

3 3 2
1 4
0 1 3
1 1 2
5 2 3

输出

10

备注

【样例说明】
对 D2 使用 2 个加速器,从 2 号景点到 3 号景点时间变为 2 分钟。
公交车在第 1 分钟从1 号景点出发,第 2 分钟到达 2 号景点,第 5 分钟从2 号景点出发,第 7 分钟到达 3 号景点。
第 1 个旅客旅行时间 7-0 = 7 分钟。
第 2 个旅客旅行时间 2-1 = 1 分钟。
第 3 个旅客旅行时间 7-5 = 2 分钟。
总时间 7+1+2 = 10 分钟。

【数据范围】
对于 10% 的数据,k=0;
对于 20% 的数据,k=1;
对于 40% 的数据,2 ≤n≤50,1≤m≤1,000,0≤k≤20,0≤Di≤10,0≤Ti≤500;
对于 60% 的数据,1≤n≤100,1≤m≤1,000,0≤k≤100,0≤Di≤100,0≤Ti≤10,000;
对于 100% 的数据,1≤n≤1,000,1≤m≤10,000,0≤k≤100,000,0≤Di≤100,0≤Ti≤100,000。

       观光公交解题报告

       这道题目就是一个纯正的贪心的题目,就是每一次都用每一个最优的方案,就是真正的最优解,

其实在使用加速器的时候,就是贪心的使用……

      本题还有一个优化,就是不用到最后在计算m个人的总时间了,直接在中间就计算完了,……

var d:array[1..1001] of longint;
    arrive,last,off:array[1..1001] of longint;
    n,m,i,j,k,ans,more,best:longint;
    x,y,t,tot:longint;
    f:array[1..1001] of longint;
function max(x,y:longint):longint;
begin
  if x>y then exit(x) else exit(y);
end;
begin
       assign(input,'bus.in');reset(input);
       assign(output,'bus.out');rewrite(output);
      readln(n,m,k);
    for i:=1 to n-1 do read(d[i]);
    for i:=1 to m do
     begin
      readln(t,x,y);
      tot:=tot+t;
      if t>last[x] then last[x]:=t;
      off[y]:=off[y]+1;
     end;
   for i:=1 to n-1 do
    begin
     arrive[i+1]:=max(arrive[i],last[i])+d[i];
     ans:=ans+arrive[i+1]*off[i+1];
    end;
   ans:=ans-tot;
  while k>0 do
   begin
     dec(k);
     f[n]:=0; more:=0;
     for i:=n-1 downto 1 do
      begin
       if arrive[i+1]<=last[i+1] then f[i]:=off[i+1]
        else f[i]:=f[i+1]+off[i+1];
       if (d[i]>0)and(f[i]>more) then
         begin
           more:=f[i];
           best:=i;
         end;
      end;
     if more=0 then break;
     dec(ans,more);
     dec(d[best]);
     for i:=best+1 to n do
      begin
        dec(arrive[i]);
        if arrive[i]<last[i] then break;
      end;
   end;
   writeln(ans);
   close(input); close(output);
end.

欢迎赞赏!………………

 评价……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值