2017.7.6 C组总结

77 篇文章 0 订阅
37 篇文章 0 订阅

NO.1

题目描述:
Mirko 最近发现了一个古老的游戏。这个游戏的屏幕有N列。在屏幕的底部,有个占M(M< N)列的船。在玩这个游戏的过程中,我们可以左右移动这条船,但是这条船必须时刻完整的在屏幕里面。这条船开始的时候是在最左边的。
有一些苹果从这个屏幕的顶部掉下来,每个苹果会从屏幕N列中的某一列的顶部掉下来,垂直下落直到到达屏幕的底部。当前一个苹果掉落在底部以后,后一个苹果开始下落。
一个苹果被船接到是这么定义的:这条船占有这个苹果掉下来的那一列。我们的目标是接到所有的苹果,在这种情况下,我们要求在所有苹果的掉落过程中,尽量减少船的移动总距离。

思路:定义两个变量 l 和 r,表示船两端的位置
从x掉下来苹果,如:①在船的上方,不用移动
②在船的左方,那么移动步数为l-x,l=x r=l+m-1
③在船的右手,那么移动步数为x-r, r=x l=r-m+1
一直模拟就可以A

代码:

var  n,m,j,l,r,i,ans,x:longint;
begin
  readln(n,m);
  readln(j);
  l:=1;
  r:=m;
  for i:=1 to j do
    begin
      readln(x);
      if r<x then
        begin
          ans:=x-r+ans;
          r:=x;
          l:=r-m+1;
        end;
      if l>x then
        begin
          ans:=l-x+ans;
          l:=x;
          r:=l+m-1;
        end;
    end;
  write(ans);
end.

NO.2

题目描述:
总所周知,我们住在一个N*N的方阵(正方形)里面。其中每个小格子中都有一个整数。为了离开这个方阵,我们必须找到最美丽的子方阵。
如果我们定义A为某个方阵主对角线上的和,定义B为某个方阵副对角线上的和,那这个方阵的美丽值就是A-B。

思路:前缀和
设x[i,j]为到左上角的对角线,状态转移方程为x[i,j]=x[i-1,j-1]+a[i,j]
设y[i,j]为到右上角的对角线,状态转移方程为y[i,j]=y[i-1,j+1]+a[i,j]
然后用三重循环来枚举右下角的坐标和矩阵边长,那么这个矩阵的美丽值为(x[i,j]-x[i-k,j-k])-(y[i,j-k+1]-y[i-k,j+1])

代码:

uses math;
var n,i,j,k,ans:longint;
    a,x,y:array[0..401,0..401]of longint;
begin
  fillchar(x,sizeof(x),#0);
  fillchar(y,sizeof(y),#0);
  readln(n);
  for i:=1 to n do
    begin
      for j:=1 to n do begin read(a[i,j]); x[i,j]:=x[i-1,j-1]+a[i,j]; end;
      readln;
    end;
  for i:=1 to n do
    for j:=n downto 1 do
      y[i,j]:=y[i-1,j+1]+a[i,j];
   for i:=2 to n do
     for j:=2 to n do
       for k:=2 to min(i,j) do
         ans:=max(ans,(x[i,j]-x[i-k,j-k])-(y[i,j-k+1]-y[i-k,j+1]));
  write(ans);
end.

NO.3

题目描述:
在舞会上有N个男孩和N个女孩,每个人都量过了自己的身高。每个男孩只跟女孩跳舞,并且女孩也只跟男孩跳舞。每个人最多只有一个舞伴。男孩或者想和比自己高的女孩跳舞,或者想和比自己低的女孩跳舞,同样的,女孩也是或者想和比自己高的男孩跳舞,或者想和自己低的男孩跳舞
你能决定最多有多少对能在一起跳舞么?

思路:快排+暴力模拟
首先将男生从大到小排序,女生从小到大排序
然后在找出男生、女生正和负的分界点x1、x2(Tips:如果没找到就设为n+1)
分两个循环枚举,其时间复杂度为O(n)
①定义l=1,来枚举女生
循环i:1~x1-1
如果b[i]

var n,i,l,ans,x1,x2:longint;
    b,g:array[0..100001]of longint;

procedure qsort(l,r:longint);
var i,j,mid:longint;
begin
  if l>=r then exit;
  i:=l; j:=r; mid:=b[(l+r) div 2];
  repeat
    while b[i]>mid do inc(i);
    while b[j]<mid do dec(j);
    if i<=j then
      begin
        b[0]:=b[i];
        b[i]:=b[j];
        b[j]:=b[0];
        inc(i);
        dec(j);
      end;
  until i>j;
  qsort(l,j);
  qsort(i,r);
end;

procedure qsort1(l,r:longint);
var i,j,mid:longint;
begin
  if l>=r then exit;
  i:=l; j:=r; mid:=g[(l+r) div 2];
  repeat
    while g[i]<mid do inc(i);
    while g[j]>mid do dec(j);
    if i<=j then
      begin
        g[0]:=g[i];
        g[i]:=g[j];
        g[j]:=g[0];
        inc(i);
        dec(j);
      end;
  until i>j;
  qsort1(l,j);
  qsort1(i,r);
end;

begin
  readln(n);
  for i:=1 to n do read(b[i]);
  readln;
  for i:=1 to n do read(g[i]);
  qsort(1,n);
  qsort1(1,n);
  for i:=1 to n do
    begin
      if (b[i]<0)and(x1=0) then x1:=i;
      if (g[i]>0)and(x2=0) then x2:=i;
      if (x1<>0)and(x2<>0) then break;
    end;
  if x1=0 then x1:=n+1; if x2=0 then x2:=n+1; 
  l:=1;
  for i:=1 to x1-1 do
    begin
      if l>x2 then break;
      if abs(b[i])<abs(g[l]) then begin inc(ans);inc(l); end;
    end;
  l:=x2;
  for i:=x1 to n do
    begin
      if l>n then break;
      if abs(b[i])>abs(g[l]) then begin inc(ans);inc(l); end;
    end;
  write(ans);
end.

NO.4

题目描述:
金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。今天一早,金明就开始做预算了,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:

主件 附件
电脑 打印机,扫描仪
书柜 图书
书桌 台灯,文具

如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有0个、1个或2个附件。附件不再有从属于自己的附件。金明想买的东西很多,肯定会超过妈妈限定的N元。于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。他还从因特网上查到了每件物品的价格(都是10元的整数倍)。他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。
设第j件物品的价格为v[j],重要度为w[j],共选中了k件物品,编号依次为j1,j2,……,jk,则所求的总和为:
v[j1]w[j1]+v[j2]*w[j2]+ …+v[jk]*w[jk]。(其中为乘号)
请你帮助金明设计一个满足要求的购物单。

思路:DP大法
设f[i,j]为取到第i个,用了j的价钱的最大价值
如果为附件或买不起,则f[i,j]:=f[i-1,j];
如果为主件,则有三种情况:
①只取主件,f[i,j]:=max(f[i-1,j],f[i-1,j-v[i]]+w[i]*v[i]);;
②取主件和附件一(要枚举的j>=主件的价钱和附件一的费用,而且要该主件有附件一), f[i,j]:=max(f[i,j],f[i-1,j-v[i]-v[fj[i,1]]]+w[i]*v[i]+w[fj[i,1]]*v[fj[i,1]]);;
③取主件和附件二(j>=主件和附件二的费用,而且该主件有附件二), f[i,j]:=max(f[i,j],f[i-1,j-v[i]-v[t2]]+w[i]*v[i]+w[t2]*v[t2]);
④取主件和附件一二(j>=主件和附件一二的费用,而且该主件有附件一和二),f[i,j]:=max(f[i,j],f[i-1,j-v[i]-v[t1]-v[t2]]+w[i]*v[i]+w[t1]*v[t1]+w[t2]*v[t2]);

代码:

uses math;
var f:array[0..60,0..32000] of int64;
    fj:array[0..60,1..2] of longint;
    w,v,num,q:array[1..60] of longint;
    i,j,x,y,z,k,m,n,p,t1,t2:longint;sum:int64;
begin
  assign(input,'budget.in');
  assign(output,'budget.out');
  reset(input);
  rewrite(output);
  readln(n,m);
  for i:=1 to m do
    begin
      readln(v[i],w[i],q[i]);
      if q[i]>0 then
        begin
          inc(num[q[i]]);
          fj[q[i],num[q[i]]]:=i;
        end;
    end;
  for i:=1 to m do
    for j:=0 to n do
      if (v[i]>j)or(q[i]>0) then f[i,j]:=f[i-1,j]
      else
        begin
          f[i,j]:=max(f[i-1,j],f[i-1,j-v[i]]+w[i]*v[i]);
          if num[i]>=1 then if j-v[i]-v[fj[i,1]]>=0 then
              f[i,j]:=max(f[i,j],f[i-1,j-v[i]-v[fj[i,1]]]+w[i]*v[i]+w[fj[i,1]]*v[fj[i,1]]);
          if num[i]=2 then
            begin
              t1:=fj[i,1];
              t2:=fj[i,2];
              if j-v[i]-v[t2]>=0 then f[i,j]:=max(f[i,j],f[i-1,j-v[i]-v[t2]]+w[i]*v[i]+w[t2]*v[t2]);
              if j-v[i]-v[t1]-v[t2]>=0 then f[i,j]:=max(f[i,j],f[i-1,j-v[i]-v[t1]-v[t2]]+w[i]*v[i]+w[t1]*v[t1]+w[t2]*v[t2]);
            end;
        end;
  writeln(f[m,n]);
  close(input);
  close(output);
end.
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值