USACO 2014 FEB 银组

时间:2023-03-10 00:41:49
USACO 2014 FEB 银组

1.自动打字{Silver1}

【问题描述】

贝西新买了手机,打字不方便,请设计一款应用,帮助她快速发消息。

字典里有W(W<=30000)个小写字母构成的单词,所有单词的字符总数量不超过1,000,000,这些单词是无序的。现在给出N(1 <= N <= 1000)个询问,每个询问i包含一个的字符串s_i(每个字符串最多包含1000个字符)和一个整数K_i,对于所有以s_i为前缀的单词,其中按字典序排序后的第K_i个单词,求该单词在原字典里的序号。

【文件输入】

第一行为两个整数W和N。

接下来2..W+1行,每行一个单词;

接下来W+2..W+N+1行,一个整数和一个字符串,分别表示K_i和s_i。

【文件输出】

输出共N行,每行一个整数,表示位置,如果无解则输出-1。

【输入样例】

10 3

dab

ba

ab

daa

aa

aaa

aab

abc

ac

dadba

4 a

2 da

4 da

【输出样例】

3

1

-1

【样例说明】

以a为前缀的单词有{aa,aaa,aab,ab,abc,ac},第4个是ab,它在原字典中的位置是3,以da为前缀的单词有{daa,dab,dadba},第2个是dab,它在原字典中的位置是1,以da为前缀的第4个单词不存在。

2. 路障{silver2}

【问题描述】

农民约翰的农场n(1 <= N <= 250)个结点,有M(1 <= M <= 25,000)条带权值的有向边,任意两个结点之间最多有一条边相连,任意两个结点之间都有连通的路径。他的家在结点1,谷仓在结点n,他每天都从家选择最短的路径走到谷仓。

牛们开始捣乱,选择在某一条边上放置路障,使得该边的权值变为原来的2倍。求最大能使约翰多走多少路。

【文件输入】

第一行,两个用空格隔开在整数N和M。

接下来M行,每行3个整数,A_j,B_j和L_j,分别表示一条边的两个结点和权值(权值是1...1,000,000的整数)。

【文件输出】

一个整数,表示最大值。

【输入样例】

5 7

2 1 5

1 3 1

3 2 8

3 5 7

3 4 3

2 4 7

4 5 2

【输出样例】

2

【样例说明】

原来的最短路径是1-3-4-5,总长为6,将路障放置3和4之间的边上,使得该边的权值变为6,则最短路径变为1-3-5,总长为8,增加了长度2。

第一题字符串处理 排序

var w,i,j,k,m,n,p:longint;
a:array[..] of string;
num:array[..] of longint;
len:longint;
s:string;
pre:string;
ch:char;
//t:array[0..26,30000] of string;
procedure sort(l,r: longint);
var
i,j: longint;
x,y: string;
z:longint;
begin
i:=l;
j:=r;
x:=a[(l+r) div ];
repeat
while a[i]<x do
inc(i);
while x<a[j] do
dec(j);
if not(i>j) then
begin
y:=a[i];
a[i]:=a[j];
a[j]:=y;
z:=num[i];
num[i]:=num[j];
num[j]:=z;
inc(i);
j:=j-;
end;
until i>j;
if l<j then
sort(l,j);
if i<r then
sort(i,r);
end;
begin
assign(input,'auto.in');
reset(input);
assign(output,'auto.out');
rewrite(output);
readln(N,w);
for i:= to n do
readln(a[i]);
for i:= to n do
num[i]:=i;
sort(,n);
for i:= to w do
begin
readln(k,ch,pre);
//delete(pre,1,1);
for j:= to n do
begin
if a[j][]=pre[] then
begin
s:=copy(a[j+k-],,length(pre));
if s=pre then
begin
writeln(num[j+k-]);
break;
end
else
begin writeln('-1');
break;
end;
end;
end;
end;
close(input);
close(output);
end.

第二题

可以知道改变的边一定是在原最短路径上,不然John就可以按原最短路径走了。

先做一边Dijkstra 记下路径,再枚举路径,做Dijkstra。

var i,j,n,m,s,t,p,min,x,y,k,l:longint;
a:array[..,..]of longint;
d,pre:array[..]of longint;
v:array[..]of boolean;
a1,b1:longint;
ok:boolean;
procedure dijkstra(s:longint);
begin
fillchar(d,sizeof(d),$7f);
fillchar(v,sizeof(v),false);
d[s]:=;
for j:= to n do begin
min:=maxlongint;
for i:= to n do
if (not v[i]) and (d[i]<min) then
begin
p:=i;
min:=d[i];
end;
v[p]:=true;
for i:= to n do
if (not v[i])and(a[p,i]<>)and
(d[p]+a[p,i]<d[i]) then
begin
d[i]:=d[p]+a[p,i];
if not ok then pre[i]:=p;
end;
end;
end; begin
assign(input,'rblock.in');
reset(input);
assign(output,'rblock.out');
rewrite(output);
fillchar(pre,sizeof(pre),);
read(n,m);
for j:= to m do
begin
read(a1,b1,l);
if (l<a[a1,b1]) or (a[a1,b1]=) then begin
a[a1,b1]:=l;
a[b1,a1]:=l;
end;
end;
dijkstra();
ok:=true;
x:=d[n];
k:=n;
repeat
a[k,pre[k]]:=*a[k,pre[k]];
a[pre[k],k]:=a[k,pre[k]];
dijkstra();
if d[n]>y then y:=d[n];
a[k,pre[k]]:=a[k,pre[k]] div ;
a[pre[k],k]:=a[k,pre[k]];
k:=pre[k];
until k=;
writeln(y-x);
close(input);
close(output);
end.