2017.8.07 SSL 模拟赛

T1:
小游戏game:
题目大意:
有M个凳子,顺时针依次编号为1,2,3……,M。从编号为S的凳子开始,每次先顺时针数N个凳子,将第N个凳子搬走,然后再逆时针数K个凳子,将第K个凳子搬走。每次都这样先顺时针数N个,再逆时针数K个,直到搬完,求M个凳子的搬走顺序。

100%:
M<=1000

题解:
模拟:
按着他的要求模拟着走,因为数据只有1000,所以这样也不会炸,然后注意一下边界,越界则:
s=0 则 s=m
s=m+1 则 s=1
然后就可以了。
时间复杂度:O(M/2*(N+K))

var
     i,j,l,m,s,n,k:longint;
     flag:array [0..1001] of boolean;
begin
     readln(m);
     readln(s);
     readln(n);
     readln(k);
     j:=0;
     repeat

          if s=m+1 then s:=1;
          while flag[s] do
          begin
               inc(s);
               if s=m+1 then s:=1;
          end;
          l:=1;
          while l<n do
          begin
               inc(s);
               if s=m+1
                  then s:=1;

               if not(flag[s])
                  then inc(l);
          end;
          flag[s]:=true;
          write(s,' ');
          inc(j);
          dec(s);

          if j=m then break;

          if s=0 then s:=m;
          while flag[s] do
          begin
               dec(s);
               if s=0 then s:=m;
          end;
          l:=1;
          while l<k do
          begin
                dec(s);
                if s=0
                   then s:=m;
                if not(flag[s])
                   then inc(l);
          end;
          flag[s]:=true;
          write(s,' ');
          inc(j);
          inc(s);

     until j=m;
end.

T2:
约数个数shlqsh:
我们设f(x)表示x的约数个数。
我们给出一段区间[a,b],求f[a],f[a+1]…f[b]的∑。

对于50%的数据,1≤a≤b≤1000;
对于100%的数据,1≤a≤b≤10,000,000

题解:
50分的做法:
直接枚举每个数的约数,然后累加。
100分的做法:
我们发现这题本质上就是求,对于一个x的倍数y,它在[a,b]这段区间中,出现了多少个。
//1≤x≤b
a≤y≤b

然后
①我们就可以直接去求里面出现了多少个,在里面找到第一个出现的x的倍数,然后去推。
亦或者
②对于[a,b]中的x的倍数的总数的个数,其实就是
1~b的x的倍数的个数,减去1~a-1的x的倍数的个数,这个可以直接枚举一下。
时间复杂度:O(A+B)
我用的是①,第二个方法也挺简单的,脑补一下就会了

var
    i,j,sum,a,b:longint;
begin
    readln(a,b);
    for i:=1 to b do
    begin
         j:=i*(a div i);
         if j=a then inc(sum);
         sum:=sum+(b-j) div i;
    end;
    writeln(sum);
end.

T3:
机器选择selc:
题目大意:
在一个连通图中有N个点,找一个点,使得这个点到每个点的最短路的最大值最小,求这个最小的最大值。
保证任意两点间有且仅有一条路径

对于30%的数据,n≤100;
对于50%的数据,n≤1000;
对于100%的数据,2≤n≤100000

题解:
这题其实就是求一个树上最长链,然后取半
怎么求树上最长链呢?
有人有反证法证出:
对于一个树的最长链:
我们要先从任意一个点a出发,找到以它为起点构成的连通图中,到它这个点最长距离的点是哪个。
设这个点为b,
则这个点必定是这条树上最长链的一个端点:
然后我们从B点出发,重新以B点为起点,遍历一遍整个图,这时候离它最远的那个点则为另一个端点,构成的那条树链接则为最长链。

证明:
http://blog.csdn.net/macuilxochitl/article/details/19157579

因为遍历没有重复所以每一次遍历时间复杂度为:
O(N),然后要遍历2遍。

最后输出最长链折半要注意,+1再 div 2,为什么自行脑补。

var
    s,t,list,next:array [0..200001] of longint;
    max:array [1..2] of longint;
    i,j,n,p:longint;

procedure dfs(dep,kep,rp:longint);
var
    i:longint;
begin
    i:=list[dep];
    if kep>max[1] then
    begin
         max[1]:=kep;
         max[2]:=dep;
    end;
    while i>0 do
    begin
         if t[i]<>rp then
            dfs(t[i],kep+1,dep);
         i:=next[i];
    end;
end;

begin
    readln(n);
    for i:=1 to n-1 do
    begin
         inc(p);
         readln(s[p],t[p]);
         next[p]:=list[s[p]];
         list[s[p]]:=p;

         inc(p);
         s[p]:=t[p-1];
         t[p]:=s[p-1];
         next[p]:=list[s[p]];
         list[s[p]]:=p;
    end;

    max[1]:=0; max[2]:=0;
    dfs(1,0,0);
    max[1]:=0;
    dfs(max[2],0,0);
    writeln((max[1]+1) div 2);
end.

T4:
WJ的逃离escape:
题目大意:
WJ被困在在一个r*c地图的左上角,迷宫的右下角为出口,整个地图有些地方会有障碍无法通过,WJ想知道到达出口最少需要几次转弯。

保证至少有一条路径可以到达出口,且左上角右下角没有障碍。
对于20%的数据,r、c≤10;
对于40%的数据,r、c≤100;
对于100%的数据,r、c≤500。

题解:
这题不难发现,就是一个宽搜:
对于每个点我们记录到此点的最优答案,并直接向四周拓展。
为什么?
因为第一次找到的点得到的保证是最优解,所以找到出口就可以直接输出halt。
又因为我们搜的是转弯,而如果走一个方向其实就等于转了个弯,这时候要+1。

然后莫名其妙WA了好久,随便改改,A的一声~

const
  dx:array [1..4] of integer=(-1,0,1,0);
  dy:array [1..4] of integer=(0,1,0,-1);

var
  h,a:array [0..501,0..501] of boolean;
  p:array [0..250001] of longint;
  q:array [0..250001,1..2] of longint;
  i,j,n,m:longint;
  d:char;

function check(x,y:longint):boolean;
begin
     if (x<1) or (x>n) or (y<1) or (y>m) or (a[x,y]) then exit(false);
     exit(true);
end;


procedure bfs;
var
    head,tail,x,y,i,k:longint;
begin
     head:=0;
     tail:=1;
     q[1,1]:=1;
     q[1,2]:=1;
     p[1]:=0;
     while head<tail do
     begin
         inc(head);
         for k:=1 to 4 do
         begin
              x:=q[head,1]+dx[k];
              y:=q[head,2]+dy[k];
              while check(x,y) do
              begin
                     if not(h[x,y]) then
                     begin
                          h[x,y]:=true;
                          inc(tail);
                          p[tail]:=p[head]+1;
                          q[tail,1]:=x;
                          q[tail,2]:=y;
                          if (q[tail,1]=n) and (q[tail,2]=m)
                          then begin
                                  writeln(p[tail]-1);
                                  halt;
                               end;
                      end;
                   x:=x+dx[k];
                   y:=y+dy[k];
              end;
         end; 
      end;
end;


begin
     readln(n,m);
     for i:=1 to n do
     begin
         for j:=1 to m do
         begin
              read(d);
              if d='*' then a[i,j]:=true;
         end;
         readln;
     end;
     bfs;
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值