您的位置:首页 > 其它

2017.8.07 SSL 模拟赛

2017-08-07 20:37 134 查看
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:
120c6
=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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: