JZOJ2017.08.12 C组

T1

题目描述

Windows中的扫雷游戏是大家都熟悉的小游戏,今天,味味也设计了一个简易的扫雷游戏。味味设计的扫雷游戏功能如下:
1.程序一开始会读入扫雷区域大小n,表示游戏区域有n*n个小方格组成,接下来会读入n行信息,每行有n个整数(每个整数可能是0,也可能是1),每两个整数之间用一个空格分隔。其中0 所在位置表示该小方格内没有地雷,1 所在位置表示该小方格内有地雷(游戏开始时,扫雷区域中必定包含至少一个地雷)。
接下来每行输入两个用空格分开的正整数i和j,每一行的一对i和j表示用户用鼠标单击扫雷区域中第i 行第j 列位置上的小方格(就象我们使用Windows 中扫雷游戏一样),i 和j 表的位置必定在扫雷区域内。程序每输入一对i和j,就马上进行相应的处理(就象我们在Windows 中鼠标单击某个小方块就会出现结果一样)。
2.程序将根据读入的一组i 和j的值来对扫雷区域作相应处理,具体的处理规则如下: 
(1)如果i和j 表示的小方格内没有地雷、而且也没有被处理过(就是第i行第j 列的数值
是0),那么将以该小方格为中心的一个正方形区域内所有没有地雷的小方格都赋值为-1(表示该区域的地砖已经被掀开了)。如果在当前正方形区域内有一个位置号为i1和j1(注意:i1<>i并且(1<>j)的小方格内恰好有地雷,则此地雷就被顺利扫除,将该位置标记为-2。如果该正方形区域内某些小方格已经被处理过,则对这些小方格不再做任何处理。举个例子来说明一下,假如输入信息如下左边所示,那么处理结果就如下右边所示:
(2)如果i 和j 表示的小方格已经被处理过(就是第i 行第j 列的数值是-1 或者是-2),那么不作任何处理,继续去读取下一行的i和j 的值。
(3)如果i和j 表示的小方格刚好有地雷,并且该小方格没有被处理过(就是第i 行第j 列的数值是1),那么表示用户触雷,马上输出信息“GAME OVER!”,程序结束。
3.如果在读入i和j的过程中一直没有触雷,那么就一直按照位置信息处理下去,直到满足下列条件之一,就输出相应信息并结束程序:
(1)读入的i和j的值都是0(表示用户不再在某个小方格内单击鼠标右键了),则输出处理后整个扫雷区域的状态(就是输出n行n列的方阵,每行中两个整数之间用一个空格分隔,末尾没有多余空格),然后程序结束。
(2)如果某次处理完后,游戏区域内所有的地雷都被扫除了,那么不必再读入下一行的信息,输出信息“YOU ARE WINNER!”,程序结束。

输入

输入文件名为mine.in。第一行一个整数n(n<=50),接下来是一个n*n 的方阵。再接下来是若干行,每行空格分隔的两个整数,表示i和j,以0 0结束。

输出

输出文件名为mine.out。包含一行,可能输出“YOU ARE WINNER!”,可能输出“GAME OVER!”,
也可能输出一个处理后的方阵。

思路:

较复杂的模拟,题目说什么就做什么。

代码:

var a:array[0..100,0..100] of longint;
    i,j,n,t:longint;

procedure print;
var i,j:longint;
begin
  for i:=1 to n do begin for j:=1 to n do write(a[i,j],' '); writeln; end;
end;
procedure sign(x,y:longint);
begin
  if a[x,y]=0 then a[x,y]:=-1 else
  if a[x,y]>-1 then begin a[x,y]:=-2; dec(t); end;
end;
begin
  assign(input,'mine.in');
  assign(output,'mine.out');
  reset(input);
  rewrite(output);
  read(n);
  for i:=1 to n do for j:=1 to n do begin read(a[i,j]); if a[i,j]=1 then inc(t); end;
  i:=1; j:=1;
  while (i<>0)and(j<>0) do
  begin
    read(i,j);
    if (i=0)and(j=0) then begin print; close(input); close(output);halt; end;
    case a[i,j] of
      0:
      begin
        a[i,j]:=-1;
        sign(i+1,j+1); sign(i+1,j); sign(i,j+1);
        sign(i+1,j-1); sign(i-1,j+1);
        sign(i-1,j-1); sign(i,j-1); sign(i-1,j);
        if t=0 then
        begin
          write('YOU ARE WINNER!');
          close(input); close(output);
          halt;
        end;
      end;
      1:
      begin
        write('GAME OVER!');
        close(input); close(output);
        halt;
      end;
    end;
  end;
  close(input); close(output);
end.

T2

题目描述

味味最近对树很感兴趣,什么是树呢?树就是有n个点和n-1条边形成的无环连通无向图。
今年2012年浙江省队选拔赛中味味发现了一个树中最长链(就是树当中距离最远的点对)试题,于是她着手对树进行了一些研究和思考。
味味在研究过程中想知道,对于一个无根树,当节点i作为根的时候树的高是多少。所谓树高指的是从根节点出发,到离根节点最远叶子节点所经过的节点的总数,详见输入输出样例1。
味味现在遇到了一些烦心的事情,不想再继续思考了,请你帮助她解决这个问题。

输入

输入文件名为 tree.in,共 N 行。第一行为一个正整数 N,表示树的节点个数。第2 行到第 N行里,每行两个用空格隔开的正整数a 和b,表示a 与b有连边。

输出

输出文件 tree.out 共N 行,第i行表示以节点i为根时的树高。

思路:

枚举根节点,深搜,AC!!!

代码:

uses math;
var n,i,x,y,ans:longint;
    a:array[0..1010,0..1010] of longint;
procedure dfs(f,s,dep:longint);
var i:longint;
begin
  if (a[s,0]<1) then begin ans:=max(dep,ans); exit; end else
  if (dep>1)and(a[s,0]<=1) then begin ans:=max(dep,ans); exit; end;
  for i:=1 to a[s,0] do
    if (a[s,i]<>f) then dfs(s,a[s,i],dep+1);
end;
begin
  assign(input,'tree.in');
  assign(output,'tree.out');
  reset(input);
  rewrite(output);
  read(n);
  for i:=1 to n-1 do
  begin
    read(x,y);
    inc(a[x,0]); a[x,a[x,0]]:=y;
    inc(a[y,0]); a[y,a[y,0]]:=x;
  end;
  for i:=1 to n do begin ans:=0; dfs(0,i,1);  writeln(ans); end;
  close(input);
  close(output);
end.

题目描述

味味有一个A×B×C 的长方体积木,积木是有1×1×1 的小积木块组成的。我们设定这个长方体的高为A,宽为B,长为C。(为方便起见,长方体的长不一定要比宽的数值大)。
现在味味在这个长方体中的的左上角挖去了一个(A-1)×(B-2)×(C-2)的小长方体。并且告诉你被挖去长方体的体积为n,即n=(A-1)×(B-2)×(C-2)。现在问你,被挖去小长方体后,原有长方体积木中剩下的1×1×1的小积木块最少和最多分别是多少个。也就是说,在告诉你n值的前提下,求min{A×B×C-n}和max{A×B×C-n}。

输入

输入文件名为 block.in。
输入共1行,仅一个正整数n。

输出

输出文件名为 block.out。
输出共1行包含两个用空格隔开的正整数,依次表示最少剩余小积木块和最多剩余小积木块个数。

思路:

先推出公式 max=8*n-9(不推也行)
再枚举min。分边枚举,过得了。在更新min(max)

代码:

var i,j,x:longint;
    max,min,n:int64;
    a:array[0..100000]of longint;
begin
  assign(input,'block.in');
  assign(output,'block.out');
  reset(input);
  rewrite(output);
  min:=maxlongint; read(n); max:=8*n+9;
  for i:=1 to trunc(sqrt(n)) do
  if n mod i=0 then
  begin
    inc(x);
    a[x]:=i;
    if n div i<>i then
    begin
      inc(x);
      a[x]:=n div i;
    end;
  end;
  for i:=1 to x do
    for j:=1 to x do
      if(a[i]*a[j]*(n div a[i] div a[j])=n)
      and((n div a[i] div a[j]+2)*(a[i]+2)*(a[j]+1)-nthen
        min:=(n div a[i] div a[j]+2)*(a[i]+2)*(a[j]+1)-n;
  write(min,' ',max);
  close(input);
  close(output);
end.

T4

题目描述

4和7是味味的幸运数字。幸运数是那些只由幸运数字组成的正整数。如47,477是幸运数,而5,17,417 就不是幸运数。
定义next(x)为大于或等于x的最小的幸运数。
味味对以下表达式的值很感兴趣 :
next(L)+next(L+1)+...+next(R-1)+next(R)。
现在告诉你L和R的值,希望你能帮助味味计算出这个表达式的值。

输入

输入文件sum.in仅一行包含两个正整数L和R(1≤L≤R≤109 ),L和R的值之间用一个空格分隔。

输出

输出文件sum.out 只有一行一个整数,表示表达式的值。

思路:

因为只可能生成4和7,所以可以用二进制来生成幸运数。
然后把表达式相加就好了。

代码:

uses math;
var l,r,l1,r1,t:longint;
    ans:array[0..51] of int64;
    a:array[0..5001] of int64;
procedure jia(x:int64);
var i:longint;
begin
  i:=1;
  ans[i]:=ans[i]+x;
  while ans[i]>9 do
  begin
    ans[i+1]:=ans[i] div 10+ans[i+1];
    ans[i]:=ans[i] mod 10;
    inc(i);
  end;
  t:=max(i,t);
end;
procedure init;
var i,j,t:longint;
begin
  read(l,r);
  j:=0;
  for i:=2 to 2047 do
  begin
    inc(j);
    t:=i;
    while t>1 do
    begin
      case t mod 2 of
        0:a[j]:=a[j]*10+4;
        1:a[j]:=a[j]*10+7;
      end;
      t:=t div 2;
    end;
    if (l<=a[j])and(l1=0) then l1:=j;
    if (r<=a[j])and(r1=0) then r1:=j;
  end;
end;
procedure main;
var i:longint;
begin
  t:=1;
  jia((min(r,a[l1])-l+1)*a[l1]);
  for i:=l1+1 to r1-1 do jia((a[i]-a[i-1])*a[i]);
  if l1<>r1 then jia((r-max(l,a[r1-1]))*a[r1]);
  for i:=t downto 1 do write(ans[i]);
end;
begin
  assign(input,'sum.in');
  assign(output,'sum.out');
  reset(input);
  rewrite(output);
  init;
  main;
  close(input);
  close(output);
end.

T5

题目描述

给出如下定义:
1. 子矩阵: 从一个矩阵当中选取某些行和某些列交叉位置所组成的新矩阵(保持行与列的相对顺序) 被称为原矩阵的一个子矩阵。
例如,下面左图中选取第 2、 4 行和第 2、 4、 5 列交叉位置的元素得到一个 2*3 的子矩阵如右图所示。
2. 相邻的元素:矩阵中的某个元素与其上下左右四个元素(如果存在的话)是相邻的。
3. 矩阵的分值: 矩阵中每一对相邻元素之差的绝对值之和。

本题任务:给定一个 n 行 m 列的正整数矩阵,请你从这个矩阵中选出一个 r 行 c 列的子矩阵,使得这个子矩阵的分值最小,并输出这个分值。

输入

输入文件名为 submatrix.in。
第一行包含用空格隔开的四个整数 n, m, r, c,意义如问题᧿述中所述,每两个整数之间用一个空格隔开。
接下来的 n 行, 每行包含 m 个用空格隔开的整数,用来表示问题᧿述中那个 n 行 m 列的矩阵。

输出

输出文件名为 submatrix.out。
输出共 1 行,包含 1 个整数,表示满足题目᧿述的子矩阵的最小分值。

题解:

这道题如果枚举肯定会爆!
但是我们可以枚举行dp列
f[i][j]=第i行选了j列的最小分值

代码:

var a:array[0..20,0..20]of longint;
    b,y:array[0..20]of longint;
    f:array[0..20,0..20,0..20]of longint;
    i,j,k,l,n,m,r,c,ans:longint;
procedure init;
var i,j:longint;
begin
  read(n,m,r,c);
  for i:=1 to n do for j:=1 to m do read(a[i,j]);
  ans:=maxlongint;
end;
procedure dfs(t1,t2:longint);
var tot,i,j,k,t,l,x:longint;
begin
  if (t2>n) and (t1then exit;
  if t1then
  begin
    dfs(t1,t2+1);
    inc(b[0]);
    b[b[0]]:=t2;
    dfs(t1+1,t2+1);
    b[b[0]]:=0;
    dec(b[0]);
  end else
  if t1=r then
  begin
    fillchar(f,sizeof(f),$7f);
    f[0,0,0]:=0;
    for i:=0 to m-1 do
    begin
      for j:=i+1 to m do
      begin
        if j>=c then t:=c else t:=j;
        if i=0 then t:=1;
        for k:=1 to t do
        begin
          f[i,j,k]:=0;
          x:=maxlongint;
          for l:=0 to i-1 do if f[l,i,k-1]then x:=f[l,i,k-1];
          f[i,j,k]:=x;
          if i-1<0 then f[i,j,k]:=0;
          if (f[i,j,k]>ans) or (f[i,j,k]>512000) then continue;
          if k=1 then
          begin
            for l:=2 to r do
            f[i,j,k]:=f[i,j,k]+abs(a[b[l-1],j]-a[b[l],j]);
          end else
          begin
            for l:=1 to r do
              f[i,j,k]:=f[i,j,k]+abs(a[b[l],i]-a[b[l],j]);
            for l:=2 to r do
              f[i,j,k]:=f[i,j,k]+abs(a[b[l-1],j]-a[b[l],j]);
          end;
          if (k=c) and (f[i,j,k]then ans:=f[i,j,k];
        end;
      end;
    end;
  end;
end;
begin
    assign(input,'submatrix.in');
    assign(output,'submatrix.out');
    reset(input);
    rewrite(output);
    init;
    dfs(0,1);
    write(ans);
    close(input); close(output);
end.

你可能感兴趣的:(题解,jzoj)