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[0..30000] of string;
    num:array[0..30000] 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 2];
         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-1;
             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:=1 to n do
  readln(a[i]);
 for i:=1 to n do
  num[i]:=i;
 sort(1,n);
 for i:=1 to w do
  begin
   readln(k,ch,pre);
   //delete(pre,1,1);
   for j:=1 to n do
    begin
     if a[j][1]=pre[1] then
      begin
       s:=copy(a[j+k-1],1,length(pre));
       if s=pre then
       begin
       writeln(num[j+k-1]);
       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[0..1000,0..1000]of longint;
    d,pre:array[0..1000]of longint;
    v:array[0..1000]of boolean;
    a1,b1:longint;
    ok:boolean;
procedure dijkstra(s:longint);
begin
    fillchar(d,sizeof(d),$7f);
    fillchar(v,sizeof(v),false);
    d[s]:=0;
    for j:=1 to n do begin
        min:=maxlongint;
        for i:=1 to n do
            if (not v[i]) and (d[i]<min) then
            begin
                p:=i;
                min:=d[i];
            end;
        v[p]:=true;
        for i:=1 to n do
            if (not v[i])and(a[p,i]<>0)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),0);
   read(n,m);
   for j:=1 to m do
       begin
        read(a1,b1,l);
        if (l<a[a1,b1]) or (a[a1,b1]=0)  then begin
         a[a1,b1]:=l;
         a[b1,a1]:=l;
        end;
       end;
    dijkstra(1);
    ok:=true;
    x:=d[n];
    k:=n;
repeat
 a[k,pre[k]]:=2*a[k,pre[k]];
 a[pre[k],k]:=a[k,pre[k]];
 dijkstra(1);
 if d[n]>y then  y:=d[n];
 a[k,pre[k]]:=a[k,pre[k]] div 2;
 a[pre[k],k]:=a[k,pre[k]];
 k:=pre[k];
until k=0;
writeln(y-x);
close(input);
close(output);
end.
原文地址:https://www.cnblogs.com/syzcannot/p/4075444.html