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 ldo
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 ldo
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 headdo
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.