20111018 模拟赛

题目名称

Lyric

Trick

Maze

Dormitory

可执行文件名

Lyric

Trick

Maze

Dormitory

输入文件名

Lyric.in

Trick.in

Maze.in

Dormitory.in

输出文件名

Lyric.out

Trick.out

Maze.out

Dormitory.out

时限

1s

1s

1s

1s

内存限制

128M

128M

128M

128M

测试点数目

10

10

10

10

测试点分值

10

10

10

10

题目类型

传统

传统

传统

传统

Lyric

【问题描述】
痛过以后 才知情已难寻
吾爱至斯 只剩飞花梦影
回首再望 蜀山依旧伫立
看尽浮沉 独饮回忆 ——《少年情》

旋律动听的曲子,伴着意境深远的lyric而显得更加优美。要想学会一首歌,没有一份装订精美的歌词,你让我情何以堪。

你的任务是,将一份歌词,按照给出规则整理好。

【输入格式】

若干行文字(包括按规定格式给出歌曲名,歌词)

每一行格式为 标识+内容

标识[name]表示后接歌曲名

标识[mm:ss]表示后接歌词,其中m,s表示每一位数字,为歌词出现的时间。保证符合正常的计时方式。

若存在时间相同的歌词,则应按规则依次首尾相连在同一行输出,规则如下:

1、 长度短的靠前;

2、 长度相同则字典序小的靠前。

【输出格式】

第一行八个空格+歌曲名

第二行及以后按时间顺序列出歌词

【输入样例】

[00:02]she is the heaven-sent angel you met

[00:05]=.=.=.=.=

[00:04]she is so pretty all over the world

[00:01]she is the one that you never forget

[name]she

[00:03]oh,she must be the reason why God made a girl

【输出样例】

she

she is the one that you never forget

she is the heaven-sent angel you met

oh,she must be the reason why God made a girl

she is so pretty all over the world

=.=.=.=.=

【数据hint】

1、 保证歌曲名和歌词均为英文字母,字符。

2、 保证每一行不超过256个字符

3、 保证输入不超过2000行

 

//用字符串模拟恶心人
//C处理字符串的空格太麻烦了,还是写P
program lyric;
type
  node=record
    time,len:longint;
    s:ansistring;
  end;
var
  a:array[0..2100] of node;
  i,last,n,p,tt,mm:longint;
  s,m,t:ansistring;
procedure swap(var a,b:node);
  var
    c:node;
  begin
    c:=a;
    a:=b;
    b:=c;
  end;
function cmp(a,b:node):boolean;
  begin
    if (a.time<b.time) then exit(true)
    else if (a.time>b.time) then exit(false)
    else if (a.len<b.len) then exit(true)
    else if (a.len>b.len) then exit(false)
    else if (a.s<b.s) then exit(true);
    exit(false);
  end;
procedure sort(l,r:longint);
  var
    i,j:longint;
    x:node;
  begin
    i:=l;
    j:=r;
    x:=a[(l+r) shr 1];
    repeat
      while (cmp(a[i],x)) do inc(i);
      while (cmp(x,a[j])) do dec(j);
      if (i<=j) then
        begin
          swap(a[i],a[j]);
          inc(i);
          dec(j);
        end;
    until i>j;
    if (i<r) then sort(i,r);
    if (l<j) then sort(l,j);
  end;
begin
  assign(input,'lyric.in');reset(input);
  assign(output,'lyric.out');rewrite(output);
  while (not eof) do
    begin
      inc(n);
      readln(s);
      p:=pos(']',s);
      a[n].s:=copy(s,p+1,length(s)-p);
      a[n].len:=length(a[n].s);
      if (s[2]='n')and(s[3]='a')and(s[4]='m')and(s[5]='e') then
        begin
          a[n].time:=-1;
        end
        else
        begin
          //m:=copy(s,2,pos(':',s)-2);
          m:='';
          m:=m+s[2]+s[3];
          val(m,mm);
          t:='';
          t:=t+s[5]+s[6];
          //t:=copy(s,pos(':',s)+1,p-pos(':',s)-1);
          val(t,tt);
          a[n].time:=mm*100+tt;
        end;
    end;
  sort(1,n);
  write('        ',a[1].s);
  last:=-1;
  for i:=2 to n do
    begin
      if (a[i].time<>last) then
        begin
          writeln;
        end;
      write(a[i].s);
      last:=a[i].time;
    end;
  writeln;
  close(input);
  close(output);
end.

 

Trick

【题目描述】

暴躁的稻草人,最终以自爆来给我们的队伍致命一击,全队血量见底,稻草人也一分为二。还好我们有雨柔妹子,瞬间精力回满。不过事后姜小弟和龙腹黑就开始了报复。

他们读取存档,将若干暴躁的稻草人活捉。然后将它们放到一个迷宫的入口。迷宫是有向图。此刻暴躁的稻草人们在1号位置,而迷宫出口在n号位置。因为稻草人会自爆,所以他每经过一条路数量就会加倍。每条路上有敌人,会消耗稻草人c[i](c[i]为负值);当然有些时候路上也会遇到止血草之类的东西,这时候就可以补充一些稻草人咯(c[i]为正值)。如果小稻草人死光了,那么稻草人也就可以看做是挂了。希望你帮助稻姜龙二人算出用最少的初始稻草人使其能够走出迷宫。

【输入格式】

第一行两个数N(<=50000),M(<=100000)表示点位数与边数。

以下M行,每行三个数a,b,c表示从a到b两点间的边权是c(|c|<=10000)

【输出格式】

输出仅一个整数,表示最小初始稻草人数。

【输入样例】

  5 4
  1 2 -3
  1 3 -6
  3 4 1
  4 5 -9

【输出样例】

  4

 

//应该还有一种方法是只做一边SPFA,没想清,还是写个二分吧
program trick;
type
  edge=record
    x,w,next:longint;
  end;
var
  e:array[0..200000] of edge;
  k:array[0..50000] of longint;
  d:array[0..50000] of longint;
  v:array[0..50000] of boolean;
  f:array[0..1000000] of longint;
  n,m,i,j,tot,a,b,c:longint;
  l,r,mid:longint;
  flag:boolean;
procedure add(a,b,c:longint);
  begin
    inc(tot);
    e[tot].x:=b;
    e[tot].w:=c;
    e[tot].next:=k[a];
    k[a]:=tot;
  end;
function check(s:longint):boolean;
  var
    i,x,t,head,tail,cnt:longint;
  begin
    for i:=1 to n do
      begin
        d[i]:=-1;
        v[i]:=false;
      end;
    cnt:=0;
    d[1]:=s;
    v[1]:=true;
    head:=0;
    tail:=1;
    f[tail]:=1;
    while (head<tail) do
      begin
        inc(head);
        x:=f[head];
        v[x]:=false;
        t:=k[x];
        if (d[x]<=0) then continue;
        while (t<>0) do
          begin
            if (d[e[t].x]=-1) or (d[e[t].x]<d[x]*2+e[t].w) then
              begin
                d[e[t].x]:=d[x]*2+e[t].w;
                if (not v[e[t].x]) then
                  begin
                    v[e[t].x]:=true;
                    inc(tail);
                    f[tail]:=e[t].x;
                  end;
              end;
            t:=e[t].next;
          end;
      end;
    if (d[n]>0) then exit(true) else exit(false);
  end;
begin
  assign(input,'trick.in');reset(input);
  assign(output,'trick.out');rewrite(output);
  readln(n,m);
  for i:=1 to m do
    begin
      readln(a,b,c);
      add(a,b,c);
    end;
  l:=0;r:=200000;
  while (l<r) do
    begin
      mid:=(l+r) shr 1;
      flag:=check(mid);
      if not flag then l:=mid+1 else r:=mid;
    end;
  writeln(l);
  close(input);
  close(output);
end.

 

Maze

【题目描述】

众所周知(怎么又是众所周知),仙剑的迷宫是难走的要命,某人就在仙四的女罗岩困了很长时间。

我们可以把女罗岩的地图抽象成n*n的地图,我们现在在(1,1)处,而出口在(n,n)。每次行动只能向上下左右移动一格。图中有M个机关,只有打开某个机关之后,与该机关相对应的地方才可以行走。当然,地图中还会有小怪兽,他们能够监视着他所在地区以及上下左右共五个方格,我们不愿意与他们战斗(为了节省时间),所以他们能监视到的地方不可以行走。同样的,地图上的障碍物处也不能经过。

我们需要求出从起点到终点的最少步数。

【输入格式】

第1行,两个整数N, M。表示地图大小为N*N,机关的数量为M。

第2-N+1行,每行N个整数,每个整数i可能是0,-1,-2或者一个正整数。i=0表示该位置为一块空地,i=-1表示该位置为一个障碍物,i=-2表示该位置为一个小怪兽。如果i是一个属于[1,M]的正整数,则表示该位置为一个机关,其编号为i。如果i是一个大于M的正整数,则表示该位置为一个机关控制区域,它由编号为i-M的机关控制。

【输出格式】

一个整数,为走出迷宫所需的最少的步数。

【输入样例】

6 2

0 0 0 -2 -1 2

-1 0 0 0 -1 0

-2 0 0 0 3 3

-2 0 0 -1 -1 4

0 -1 0 0 -1 0

1 0 0 0 -1 0

【输出样例】

24

【样例说明】

地图如下图,S为入口,T为目标,黑色的单元格为障碍物。每个E表示一个小怪兽,(E)为小怪兽的监视范围。K1表示机关1,K2表示机关2。D1表示机关为1的控制区域,D2表示机关为2的控制区域。

最优的路线为(1,1) →(1,2) →(2,2) →(2,3) →(3,3) →(4,3) →(5,3) →(6,3) →(6,2) →(6,1)(破坏供电1) →(6,2) →(6,3) →(5,3) →(4,3) →(3,3) →(3,4) →(3,5) →(3,6) →(2,6) →(1,6)(破坏供电2) →(2,6) →(3,6) →(4.6) →(5,6) →(6,6)

clip_image001

【数据规模】

1<=N<=50

0<=M<=16

 

//二进制+BFS飘过 
#include<cstdio>
#include<cstring>
#include<cstdlib>
int di[5]={0,0,1,0,-1};
int dj[5]={0,1,0,-1,0};
int k[17]={0,1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
int n,m;
int a[52][52];
struct node{
       int x,y,n,key;
}f[1000000];
bool v[65537][52][52];
int main(){
    freopen("maze.in","r",stdin);
    freopen("maze.out","w",stdout);
    scanf("%d%d",&n,&m);
    int t;
    for (int i=1;i<=n;i++){
        for (int j=1;j<=n;j++){
            scanf("%d",&t);
            if (a[i][j]!=-1) a[i][j]=t;
            if (t==-2){
                        if (j>1) a[i][j-1]=-1;
                        if (j<n) a[i][j+1]=-1;
                        if (i>1) a[i-1][j]=-1;
                        if (i<n) a[i+1][j]=-1;
            }
        }
        scanf("\n");
    }
    int head=0,tail=1,x,y;
    f[1].x=1;
    f[1].y=1;
    v[0][1][1]=true;
    while (head<tail){
          head++;
          for (int i=1;i<=4;i++){
              x=f[head].x+di[i];
              y=f[head].y+dj[i];
              t=f[head].key;
              if (x>0&&y>0&&x<=n&&y<=n&&!v[t][x][y]){
                  if (x==n&&y==n){
                                 printf("%d\n",f[head].n+1);
                                 return 0;
                  }
                  if (a[x][y]==-1||a[x][y]==-2) continue;
                  if (a[x][y]==0){
                                 v[t][x][y]=true;
                                 f[++tail].x=x;
                                 f[tail].y=y;
                                 f[tail].n=f[head].n+1;
                                 f[tail].key=f[head].key;
                                 continue;
                  }
                  if (a[x][y]>m){
                      if ((f[head].key & k[a[x][y]-m])==k[a[x][y]-m]){
                                      v[t][x][y]=true;
                                      f[++tail].x=x;
                                      f[tail].y=y;
                                      f[tail].n=f[head].n+1;
                                      f[tail].key=f[head].key;
                                      continue;
                      }
                  }
                  if (a[x][y]<=m&&a[x][y]>0){
                      v[t][x][y]=true;
                      f[++tail].x=x;
                      f[tail].y=y;
                      f[tail].n=f[head].n+1;
                      f[tail].key=f[head].key | k[a[x][y]];
                      v[f[tail].key][x][y]=true;
                  }
              }
          }
    }
    return 0;
}

Dormitory

【题目描述】

小蛮妹子有许多的,什么棉花糖啦,蜥蜴啊,小乌龟啊,只有你想不到的没有她没有的。

小蛮妹子的小宠物都住在一个漂亮的大屋子里,每个人都有自己的床位,但是由于小蛮妹子的宠物太多了,以至于这些宠物之间并不是都互相认识。

这些宠物们也有自己的朋友,这些朋友一直羡慕他们住的漂亮大屋子,于是有一天,小蛮妹子出去玩了,一些小宠物也偷偷出去玩了,那些留守的小宠物们开始招待来访的客人。

这些来客都打算在这里住一晚上,可是安排床位就出了麻烦。每个小宠物都只愿意在自己的直接朋友或自己的床上(如果它是小蛮的宠物)睡觉,且一物睡一张床。

询问是否能有一个方案来满足所有在留宿的宠物都能住宿。

【输入格式】

第一行一个数 T 表示数据组数。

接下来 T 组数据。

每组数据第一行一个数 n 表示涉及到的总宠物数(包括小蛮的宠物和来客)。

接下来一行 n 个数,第 i 个数表示第 i 个个宠物是否是在小蛮的宠物 (0 表示不是,1 表示是)。再接下来一行 n 个数,第 i 个数表示第 i 个人是否出去玩(0 表示不出去,1 表示出去)注意如果第 i 个人不是小蛮的宠物,那么这个位置上的数是一个随机的数,你应该在读入以后忽略它)。

接下来 n 行,每行 n 个数,第 i 行第 j 个数表示 i 和 j 是否认识 (1 表示认识,0 表示不认识,第 i 行 i 个的值为 0,但是显然自己还是可以睡自己的床),认识的关系是
相互的。

【输出格式】

每一行对应每组数据

若存在方案满足条件 输出 ^.^ ,否则输出 T.T (只有三个字符,没有空格等其他内容)

【输入样例】

1

3

1 1 0

0 1 0

0 1 1

1 0 0

1 0 0

【输出样例】

^.^

【数据hint】

对于 30% 的数据满足 1 ≤ n ≤ 12。
对于 100% 的数据满足 1 ≤ n ≤ 50,1 ≤ T ≤ 20。

 

//或是个二分图最大匹配吧 
#include <cstdio>
#include <cstring>
int T;
int n;
int tot;
int map[60][60];
int list[60];
bool out[60];
int match[60];
bool use[60];
bool dfs(int x){
     for (int i=1;i<=n;i++){
         if (list[i] && map[x][i] && !use[i]){
                       use[i]=true;
                       if (match[i]==0 || dfs(match[i])){
                                        match[i]=x;
                                        return true;
                       }
         }
     }
     return false;
}
int main(){
    freopen("dormitory.in","r",stdin);
    freopen("dormitory.out","w",stdout);
    scanf("%d",&T);
    while (T--){
          memset(list,0,sizeof(list));
          memset(out,0,sizeof(out));
          memset(map,0,sizeof(map));
          scanf("%d",&n);
          for (int i=1;i<=n;i++){
              scanf("%d",&list[i]);
          }
          tot=n;
          for (int i=1;i<=n;i++){
              int x;
              scanf("%d",&x);
              if (list[i] && x==1){
                           out[i]=true;
                           tot--;
              }
          }
          for (int i=1;i<=n;i++){
              for (int j=1;j<=n;j++){
                  scanf("%d",&map[i][j]);
              }
              scanf("\n");
          }
          for (int i=1;i<=n;i++)
              if (list[i]==1) map[i][i]=1;else map[i][i]=0;
          memset(match,0,sizeof(match));
          int ans=0;
          for (int i=1;i<=n;i++){
              if (!out[i]){
                           memset(use,0,sizeof(use));
                           if (dfs(i)) ans++;
              }
          }
          if (ans==tot) puts("^.^");else puts("T.T");
    }
    return 0;
}