USACO chapter1

      几天时间就把USACO chapter1重新做了一遍,发现了自己以前许多的不足。蒽,现在的程序明显比以前干净很多,而且效率也提高了许多。继续努力吧,好好的提高自己。这一章主要还是基本功的训练,没多少的思维难度,不过基础也是很重要的。  

——2013年11月17日

 

1.1.1  Your Ride Is Here

      题目很简单,长字符串读入,按位相乘,同时取模即可,一开始的时候居然忘记了给d1和d2赋值1,结果无论是什么字符串读入计算结果都为0,虽然是水题,还是要记住初始化!

{ID: jiangyi10
PROG: ride
LANG: PASCAL
}

var
  d1,d2,i,j,k,l,m,n:longint;
  s:ansistring;

{file}
procedure openf;
begin
  assign(input,'ride.in'); reset(input);
  assign(output,'ride.out'); rewrite(output);
end;
procedure closef;
begin
  close(input); close(output);
  halt;
end;

begin
  {input}
  openf;

  {zero}
  d1:=1;
  d2:=1;

  {doit}
  readln(s);
  for i:=1 to length(s) do
  d1:=d1*(ord(s[i])-ord('A')+1) mod 47;
  readln(s);
  for i:=1 to length(s) do
  d2:=d2*(ord(s[i])-ord('A')+1) mod 47;

  {output}
  if d1=d2 then writeln('GO') else writeln('STAY');
  closef;
end.
View Code

1.1.2  Greedy Gift Givers

      暴力很容易想到,只要每次读入字符串之后循环找到其在字符串数组中的位置即可进行操作,优化的话加入链表hash即可,但是最后经过测试在USACO中暴力也可过,所以略有郁闷。

{
ID: jiangyi10
PROG: gift1
LANG: PASCAL
}

var
  now,i,j,k,l,m,n,ave:longint;
  s:array[0..1005] of ansistring;
  amount,ans:array[0..1005] of longint;

{file}
procedure openf;
begin
  assign(input,'gift1.in'); reset(input);
  assign(output,'gift1.out'); rewrite(output);
end;
procedure closef;
begin
  close(input); close(output);
  halt;
end;

begin
  {openf}
  openf;
  readln(n);
  for i:=1 to n do
  readln(s[i]);

  {doit}
  for i:=1 to n do
  begin
    readln(s[0]);
    readln(now,k);
    if k<>0 then ave:=now div k;
    for j:=1 to n do
    if s[j]=s[0] then break;
    amount[j]:=now;
    if k=0 then inc(ans[j],now)
    else inc(ans[j],now mod k);
    for j:=1 to k do
    begin
      readln(s[0]);
      for l:=1 to n do
      if s[l]=s[0] then break;
      inc(ans[l],ave);
    end;
  end;

  {output}
  for i:=1 to n do
  writeln(s[i],' ',ans[i]-amount[i]);
  closef;
end.
View Code 1
{
ID: jiangyi10
PROG: gift1
LANG: PASCAL
}
const
   modnum=99997;
type
   link=^node;
   node=record
   t:longint;
   next:link;
end;

var
  top,ave,i,j,k,l,m,n,t,mo:Longint;
  a:array[0..1005] of ansistring;
  exl:array[0..modnum-1] of link;
  st,en:array[0..1005] of longint;
  s:ansistring;

{file}
procedure openf;
begin
  assign(input,'gift1.in'); reset(input);
  assign(output,'gift1.out'); rewrite(output);
end;
procedure closef;
begin
  close(input); close(output);
  halt;
end;

{hash}
function bkdrhash(s:string):longint;
var
  i:longint;
  ans:int64;
begin
  ans:=0;
  for i:=1 to length(s) do
  ans:=((ans<<5)+ord(s[i])) and ($FFFFFFF);
  ans:=ans mod modnum;
  exit(ans);
end;

{find}
function find(s:string):longint;
var
  i,j,hash:longint;
  w:link;
begin
  hash:=bkdrhash(s);
  new(w);
  w:=exl[hash];
  if w=nil then exit(0);
  while (a[w^.t]<>s)and(w^.next<>nil) do w:=w^.next;
  if a[w^.t]=s then exit(w^.t)
  else exit(0);
end;

{add}
function add(s:string):longint;
var
  w:link;
  t,hash,i,j:longint;
begin
  hash:=bkdrhash(s);
  t:=find(s);
  if t<>0 then exit(t)
     else begin
     new(w);
     inc(top);
     a[top]:=s;
     w^.t:=top;
     w^.next:=exl[hash];
     exl[hash]:=w;
     exit(top);
  end;
end;

begin
  {input}
  openf;
  readln(n);
  for i:=1 to n do
  begin
    readln(s);
    t:=add(s);
  end;

  {doit}
  for i:=1 to n do
  begin
    readln(s);
    k:=find(s);
    readln(st[k],mo);
    if mo=0 then
      inc(en[k],st[k])
    else begin
      ave:=st[k] div mo;
      inc(en[k],st[k] mod mo);
      for j:=1 to mo do
      begin
        readln(s);
        l:=find(s);
        inc(en[l],ave);
      end;
    end;
  end;

  {output}
  for i:=1 to n do
  writeln(a[i],' ',en[i]-st[i]);
  closef;
end.
View Code 2

1.1.3  Friday the Thirteenth

      这道题主要考察蔡勒公式,一点意思都没有,注意13月14月代指1,2月,不过呢这道题告诉我重要的一点就是在取模的时候要进行加模后再取模,这样就不会导致负数取模的错误情况。

{ID: jiangyi10
PROG: friday
LANG: PASCAL
}
var
  i,j,k,l,m,n:longint;
  year,month,day,date,century:longint;
  ans:array[0..7] of longint; 

{file}  
procedure openf;
begin
  assign(input,'friday.in'); reset(input);
  assign(output,'friday.out'); rewrite(output);
end;
procedure closef;
begin
  close(input); close(output);
  halt;
end;

{getnum}
function w(year,month,century:longint):longint;
begin
  w:=((year+(year div 4)+(century div 4)-2*century+(26*(month+1)div 10)+12)+49) mod 7;
end;

begin
  {input}
  openf;
  readln(n);
  
  {doit}
  for i:=0 to n-1 do
  begin
    century:=19;
    year:=i;
    while year>=100 do
    begin
      dec(year,100);
      inc(century);
    end;
    for month:=3 to 12 do
    inc(ans[w(year,month,century)]);
    dec(year);
    if year<0 then begin
      inc(year,100);
      dec(century);
    end;
    for month:=13 to 14 do
      inc(ans[w(year,month,century)]);
  end;
  
  {output}
  write(ans[6],' ',ans[0]);
  for i:=1 to 5 do
  write(' ',ans[i]);
  writeln;
  closef;
end.
View Code

1.1.4  Broken Necklace

      首先,这道题目只要对每一个点向前搜索和向后搜索,将两次搜索之和相加即可,然后就过了,但是当数据扩大,连续相同的珠子增多时,这种方法就产生了许多的计算冗余,所以一开始在读入时就可以进行分块处理,将相同颜色的珠子直接分为一块,然后对块进行搜索即可,预计效率可以提高不少。

{ID: jiangyi10
PROG: beads
LANG: PASCAL
}
var
  max,i,j,k,l,m,n,behindlength,beforelength:longint;
  s:array[0..10000] of char;
  nowcolor:char;
procedure openf;
begin
  assign(input,'beads.in'); reset(input);
  assign(output,'beads.out'); rewrite(output);
end;
procedure closef;
begin
  close(input); close(output);
  halt;
end;
procedure searchbehind(x:longint);
begin
  if behindlength>n then exit;
  if behindlength=0 then nowcolor:=s[x];
  if (nowcolor<>s[x])and(s[x]<>'w')then exit
  else inc(behindlength);
  if x+1<=n then
  searchbehind(x+1)
  else searchbehind(1);
end;
procedure searchbefore(x:longint);
begin
  if beforelength>n then exit;
  if beforelength=0 then nowcolor:=s[x];
  if nowcolor='w' then nowcolor:=s[x];
  if(nowcolor<>s[x])and(s[x]<>'w') then exit
  else inc(beforelength);
  if x-1>0 then
  searchbefore(x-1)
  else searchbefore(n);
end;
begin
  openf;
  readln(n);
  max:=0;
  for i:=1 to n do
  read(s[i]);
  for i:=1 to n do
  begin
    behindlength:=0;
    searchbehind(i);
    beforelength:=0;
    if i-1>0 then
    searchbefore(i-1)
    else searchbefore(n);
    if beforelength+behindlength>n then begin
      writeln(n);
      closef;
    end
    else if beforelength+behindlength>max then max:=beforelength+behindlength;
  end;
  writeln(max);
  closef;
end.
View Code 1
{ID: jiangyi10
PROG: beads
LANG: PASCAL
}
var
  nowcolor,behindlength,beforelength,tmp,max,i,j,k,l,m,n,top,flag:longint;
  a:array[0..355] of char;
  block,color:array[0..355] of longint;

{file}
procedure openf;
begin
  assign(input,'beads.in'); reset(input);
  assign(output,'beads.out'); rewrite(output);
end;
procedure closef;
begin
  close(input); close(output);
  halt;
end;

{search}
procedure searchbehind(x:longint);
begin
  if behindlength>n then exit;
  if behindlength=0 then nowcolor:=color[x];
  if (nowcolor<>color[x])and(color[x]<>0)then exit
  else inc(behindlength,block[x]);
  if x+1<=top then
  searchbehind(x+1)
  else searchbehind(1);
end;
procedure searchbefore(x:longint);
begin
  if beforelength>n then exit;
  if beforelength=0 then nowcolor:=color[x];
  if nowcolor=0 then nowcolor:=color[x];
  if(nowcolor<>color[x])and(color[x]<>0) then exit
  else inc(beforelength,block[x]);
  if x-1>0 then
  searchbefore(x-1)
  else searchbefore(top);
end;

begin
  {input}
  openf;
  readln(n);
  flag:=0;
  read(a[1]);
  for i:=2 to n do begin
    read(a[i]);
    if a[i]<>a[i-1] then
    begin
      inc(top);
      block[top]:=i-1-flag;
      flag:=i-1;
      if a[i-1]='b' then color[top]:=1;
      if a[i-1]='r' then color[top]:=2;
    end;
  end;
  inc(top);
  block[top]:=n-flag;
  if a[n]='b' then color[top]:=1;
  if a[n]='r' then color[top]:=2;

  {special}
  if top=1 then
  begin
    writeln(n);
    closef;
  end;

  {doit}
  if color[top]=color[1] then
  begin
    inc(block[1],block[top]);
    dec(top);
  end;
  for i:=1 to top do
  begin
    behindlength:=0;
    searchbehind(i);
    beforelength:=0;
    if i-1>0 then
    searchbefore(i-1)
    else searchbefore(top);
    if behindlength+beforelength>max then max:=behindlength+beforelength;
  end;

  {output}
  if max>n then writeln(n) 
  else writeln(max);
  closef;
end.
View Code 2

 

1.2.1  Milking Cows

     这一题还是很裸的暴力,读入每一个区间,将其按照左端点排序,合并并去重,操作过程中同时统计两个答案,然后就可以AC了。

{ID: jiangyi10
PROG: milk2
LANG: PASCAL
}
var
  pre,ans1,ans2,k1,k2,flag,i,j,k,l,m,n:longint;
  st,en:array[0..10005] of longint;

{file}
procedure openf;
begin
  assign(input,'milk2.in'); reset(input);
  assign(output,'milk2.out'); rewrite(output);
end;
procedure closef;
begin
  close(input); close(output);
  halt;
end;

{sort}
procedure qsort(l,r:longint);
var
  i,j,mid,t:longint;
begin
  i:=l; j:=r;
  mid:=st[l+random(r-l+1)];
  repeat
    while st[i]<mid do inc(i);
    while st[j]>mid do dec(j);
    if i<=j then
    begin
      t:=st[i];
      st[i]:=st[j];
      st[j]:=t;
      t:=en[i];
      en[i]:=en[j];
      en[j]:=t;
      inc(i); dec(j);
    end;
  until i>j;
  if i<r then qsort(i,r);
  if j>l then qsort(l,j);
end;

begin
  {input}
  openf;
  readln(n);
  for i:=1 to n do
  readln(st[i],en[i]);

  {doit}
  randomize;
  qsort(1,n);
  k1:=st[1];
  k2:=en[1];
  ans1:=k2-k1;
  for i:=2 to n do
  begin
    if (st[i]<=k2)and(en[i]>k2) then k2:=en[i];
    if st[i]>k2 then begin
      if k2-k1>ans1 then ans1:=k2-k1;
      if st[i]-k2>ans2 then ans2:=st[i]-k2;
      k1:=st[i]; k2:=en[i];
    end;
  end;

  {output}
  writeln(ans1,' ',ans2);
  closef;
end.
View Code

1.2.2  Transformations

      这一题如果去判断要用哪一种方法去实现,就会变得比较困难,那么正难则反,每一种判断是否可行,也就是发现其不可行直接不考虑,最后哪种没有被删去就是这种了。

{ID: jiangyi10
PROG: transform
LANG: PASCAL
}
var
  i,j,k,l,m,n:longint;
  c:array[1..7] of boolean;
  a,b,d:array[1..10,1..10] of char;

{file}
procedure openf;
begin
  assign(input,'transform.in'); reset(input);
  assign(output,'transform.out'); rewrite(output);
end;
procedure closef;
begin
  close(input); close(output);
  halt;
end;

begin
  {input}
  openf;
  fillchar(c,sizeof(c),true);
  readln(n);
  for i:=1 to n do
  begin
     for j:=1 to n do
     read(a[i,j]);
     readln;
  end;
  for i:=1 to n do
  begin
    for j:=1 to n do
    read(b[i,j]);
    readln;
  end;
  
  {doit}
  for i:=1 to n do
  for j:=1 to n do
  begin
    if a[i,j]<>b[i,j] then c[6]:=false;
    if a[i,j]<>b[j,n-i+1] then c[1]:=false;
    if a[i,j]<>b[n-i+1,n-j+1] then c[2]:=false;
    if a[i,j]<>b[n-j+1,i] then c[3]:=false;
    if a[i,j]<>b[i,n-j+1] then c[4]:=false;
  end;
  if c[1] then writeln('1')
  else if c[2] then writeln('2')
  else if c[3] then writeln('3')
  else if c[4] then writeln('4')
  else if c[6] then writeln('6')
  else begin
    fillchar(c,sizeof(c),1);
    for i:=1 to n do
    for j:=1 to n do
    d[i,j]:=a[i,n-j+1];
    for i:=1 to n do
    for j:=1 to n do
    begin
      if d[i,j]<>b[j,n-i+1] then c[1]:=false;
      if d[i,j]<>b[n-i+1,n-j+1] then c[2]:=false;
      if d[i,j]<>b[n-j+1,i] then c[3]:=false;
    end;
    if c[1] or c[2] or c[3] then writeln('5')
    else writeln('7');
  end;
  closef;
end.
View Code

1.2.3  Name That Number

      对于一开始给出的姓名文件,我们先将其保存下来,并重新建立一个数组记录下它的数字。之后读入姓名编号之后再这个数组之中寻找这个数字,每找到一个便输出。

{ID: jiangyi10
PROG:namenum
LANG: PASCAL
}
var
  i,j,k,l,m:longint;
  n:int64;
  c:char;
  s:array[1..10000] of string;
  a:array[1..10000] of int64;
  r:longint;
  bo:boolean;
  
{file}
procedure openf;
begin
  assign(input,'namenum.in'); reset(input);
  assign(output,'namenum.out'); rewrite(output);
end;
procedure closef;
begin
  close(input);
  close(output);
  halt;
end;

{mi}
function mi(a,b:int64):int64;
var
  t,y:int64;
begin
  t:=1; y:=a;
  while b<>0 do
  begin
    if (b and 1)=1 then t:=t*y;
    y:=y*y;
    b:=b shr 1 ;
    end; exit(t);
end;

begin
  {input}
  bo:=false;
  assign(input,'dict.txt'); reset(input);
  for i:=1 to 4617 do
  begin
    readln(s[i]);
    for j:=1 to length(s[i]) do
    begin
    if (s[i][j]='A')or(s[i][j]='B')or(s[i][j]='C')then r:=2
    else if (s[i][j]='D')or(s[i][j]='F')or(s[i][j]='E')then r:=3
    else if (s[i][j]='G')or(s[i][j]='H')or(s[i][j]='I')then r:=4
    else if (s[i][j]='J')or(s[i][j]='K')or(s[i][j]='L')then r:=5
    else if (s[i][j]='M')or(s[i][j]='N')or(s[i][j]='O')then r:=6
    else if (s[i][j]='P')or(s[i][j]='R')or(s[i][j]='S')then r:=7
    else if (s[i][j]='T')or(s[i][j]='U')or(s[i][j]='V')then r:=8
    else if (s[i][j]='W')or(s[i][j]='X')or(s[i][j]='Y')then r:=9;
      a[i]:=r*mi(10,length(s[i])-j)+a[i];
    end;
  end;
  close(input);
  openf;
  readln(n);
  
  {output}
  for i:=1 to 4617 do
  if a[i]=n then
  begin
    bo:=true;
    k:=i;
    break;
  end;
  if not bo then writeln('NONE')
  else for i:=k to 4617 do
  begin
  if a[i]=n then
  writeln(s[i]);
  end;
   closef;
end.
View Code

1.2.4  Palindromic Squares

      对于这道题目,枚举1至300,同时计算出平方的进制,判断是否是回文,是则生成那个进制数并输出。在字符串转化时有一个神奇的处理方法,就是定义一个常量字符s=‘0123456789ABCDEFGHIJKLMN’在进制转化时直接取模在s中取位即可。

{ID: jiangyi10
PROG: palsquare
LANG: PASCAL
}
var
  i,j,k,l,m,n,o:longint;
  a,b:array[1..10000] of char;
  s:string;
  bo:boolean;

{file}
procedure openf;
begin
  assign(input,'palsquare.in'); reset(input);
  assign(output,'palsquare.out'); rewrite(output);
end;
procedure closef;
begin
  close(input); close(output);
  halt;
end;

begin
  {input}
  openf;
  readln(n);
  
  {doit}
  s:='0123456789ABCDEFGHIJKL';
  for i:=1 to 300 do
  begin
    bo:=true;
    j:=i*i;
    k:=0;
    o:=0;
    while j<>0 do
    begin
      inc(k);
      a[k]:=s[j mod n+1];
      j:=j div n;
    end;
    for j:=1 to k do
    if a[j]<>a[k-j+1]
      then bo:=false;
    if bo then
    begin
      m:=i;
      while m<>0 do
      begin
        inc(o);
        b[o]:=s[m mod n+1];
        m:=m div n;
      end;
      for j:=o downto 1 do
      write(b[j]);
      write(' ');
      for j:=1 to k do
      write(a[j]);
      writeln;
    end;
  end;
  closef;
end.
View Code

1.2.5  Dual Palindromes

     欣喜地发现这道题和上一道题是一模一样的方法,只要用字符串处理法就可以轻松解决进制转化,剩下的就是模拟了。

{ID: jiangyi10
PROG:dualpal
LANG: PASCAL
}
var
  i,j,k,l,m,n,o,p:longint;
  a:array[1..10000] of char;
  s:string;
  bo:boolean;
  
{openf}
procedure openf;
begin
  assign(input,'dualpal.in'); reset(input);
  assign(output,'dualpal.out'); rewrite(output);
end;
procedure closef;
begin
  close(input); close(output);
  halt;
end;

begin
  {input}
  openf;
  readln(n,m);
  s:='0123456789ABCDEFGHIJKL';
  
  {doit}
  while n<>0 do
  begin
    inc(m);
    o:=0;
    for i:=2 to 10 do
    begin
      k:=m;
      j:=0;
      while k<>0 do
      begin
        inc(j);
        a[j]:=s[k mod i+1];
        k:=k div i;
      end;
      bo:=true;
      for l:=1 to j do
      if a[l]<>a[j-l+1] then bo:=false;
      if bo then inc(o);
      if o>= 2 then begin
      writeln(m);  dec(n);
      break;
      end;
    end;
    end;
  closef;
end.
View Code

 

1.3.1  Mixing Milk

     一开始看到题目以为是DP的背包,但是仔细一看,这原来只是一道非常简单的贪心,将数据按照价值排序,从小到大进行处理,最后输出答案即可。

{ID: jiangyi10
PROG:milk
LANG: PASCAL
}
var
  ans,i,j,k,l,m,n:longint;
  v,w:array[0..10005] of longint;

{file}
procedure openf;
begin
  assign(input,'milk.in'); reset(input);
  assign(output,'milk.out'); rewrite(output);
end;
procedure closef;
begin
  close(input); close(output);
  halt;
end;

{sort}
procedure qsort(l,r:longint);
var
  i,j,mid,t:longint;
begin
  i:=l; j:=r;
  mid:=v[l+random(r-l+1)];
  repeat
    while v[i]<mid do inc(i);
    while v[j]>mid do dec(j);
    if i<=j then
    begin
      t:=v[i];
      v[i]:=v[j];
      v[j]:=t;
      t:=w[i];
      w[i]:=w[j];
      w[j]:=t;
      inc(i); dec(j);
    end;
  until i>j;
  if i<r then qsort(i,r);
  if l<j then qsort(l,j);
end;

begin
  {input}
  openf;
  readln(n,m);
  for i:=1 to m do
  readln(v[i],w[i]);
  randomize;
  qsort(1,m);

  {doit}
  i:=0;
  repeat
    inc(i);
    if w[i]<n then begin
      dec(n,w[i]);
      inc(ans,w[i]*v[i]);
    end
    else begin
      inc(ans,n*v[i]);
      n:=0;
    end;
  until n=0;

  {output}
  writeln(ans);
  closef;
end.
View Code

1.3.2

     首先根据题目,需要找M块木板,使得其盖住所有有牛的牛棚,所以呢,我们只需关心有牛的牛棚,牛棚总数对于题目没有任何的影响,但是这几块木板怎么找呢,看起来很困难,但是把题目转化一下,求M-1个牛棚之间的空缺,那么就很简单了,快排牛的位置,用最大值减去最小值加1作为答案的初始值,然后对于每两个牛的位置求差,将差排序,从最大开始从答案中减去,最后就得到答案了。需要注意的是当木板的个数大于牛棚(有牛的)个数时,直接输出牛棚个数,一开始没考虑这种特殊情况,结果导致输出了极大的负数,要引以为戒啊。

{ID: jiangyi10
PROG:barn1
LANG: PASCAL
}
var
  sum,i,j,k,l,m,n:longint;
  a,b:array[0..205] of longint;

{file}
procedure openf;
begin
  assign(input,'barn1.in'); reset(input);
  assign(output,'barn1.out'); rewrite(output);
end;
procedure closef;
begin
  close(input); close(output);
  halt;
end;

{sort}
procedure qsort(l,r:longint);
var
  i,j,mid,t:longint;
begin
  i:=l; j:=r;
  mid:=a[l+random(r-l+1)];
  repeat
    while a[i]<mid do inc(i);
    while a[j]>mid do dec(j);
    if i<=j then begin
      t:=a[i];
      a[i]:=a[j];
      a[j]:=t;
      inc(i); dec(j);
    end;
  until i>j;
  if i<r then qsort(i,r);
  if l<j then qsort(l,j);
end;

begin
  {input}
  openf;
  readln(k,m,n);
  if k>n then begin
    writeln(n);
    closef;
  end;
  for i:=1 to n do
  readln(a[i]);

  {doit}
  randomize;
  qsort(1,n);
  sum:=a[n]-a[1]+1;
  for i:=1 to n-1 do
  a[i]:=a[i+1]-a[i];
  qsort(1,n-1);
  for i:=n-1 downto n-k+1 do
  dec(sum,a[i]-1);

  {output}
  writeln(sum);
  closef;
end.
View Code

1.3.3  Calf Flac

     这道题思路还是比较清晰的,分奇数串和偶数串讨论,不用删去标点,直接在上面做,遇到标点跳过即可,主要掌握枚举单个点之后向外扩展的思想即可,不过比较坑的地方是输出,特别是计入换行符插入的地方,输出时注意一下。

{ID: jiangyi10
PROG:calfflac
LANG: PASCAL
}
var
  ans,i,j,k,l,r,m,n,al,ar,nowl,nowr,temp:longint;
  t,s:ansistring;
  bo:boolean;
  huanhang:array[0..30005] of boolean;
  
{file}
procedure openf;
begin
  assign(input,'calfflac.in'); reset(input);
  assign(output,'calfflac.out'); rewrite(output);
end;
procedure closef;
begin
  close(input); close(output);
  halt;
end;

begin
  {input}
  openf;
  readln(s);
  huanhang[length(s)] := true;
  while not eof do
  begin
    readln(t);
    s := s + t;
    huanhang[length(s)] := true;
  end;
  
  {doit}
  s := s + ',.!@#';
  n:=length(s);
  for i:=1 to length(s) do
  begin
    l:=i; r:=i; bo:=true;
    temp:=-1;
    repeat
      if (l>=1)and(r<=n) then
      begin
        al:=0;
        ar:=0;
        while (al=0)and(l>0) do
        begin
          if s[l] in ['a'..'z'] then begin
          al:=ord(s[l])-ord('a')+1;inc(temp);
          end
          else if s[l] in['A'..'Z'] then begin al:=ord(s[l])-ord('A')+1;inc(temp);end
          else dec(l);
        end;
        while (ar=0)and(r<n) do
        begin
          if s[r] in ['a'..'z'] then begin
          ar:=ord(s[r])-ord('a')+1;inc(temp);end
          else if s[r] in ['A'..'Z'] then begin ar:=ord(s[r])-ord('A')+1;inc(temp);end
          else inc(r);
        end;
        if al=ar then
        begin
          if ans<(temp) THEN
          begin ANS:=temp; nowl:=l; nowr:=r;
          end;
        end
        else bo:=false;
      end;
      dec(l); inc(r);
      if (l<1) or (r>n) then bo:=false;
    until bo=false;
    l:=i; r:=i+1; bo:=true;
    temp := 0;
    repeat
      if (l>=1)and(r<=n) then
      begin
        al:=0;
        ar:=0;
        while (al=0)and(l>0) do
        begin
          if s[l] in ['a'..'z'] then begin al:=ord(s[l])-ord('a')+1;inc(temp);end
          else if s[l] in['A'..'Z'] then begin al:=ord(s[l])-ord('A')+1;inc(temp);end
          else dec(l);
        end;
        while (ar=0)and(r<n) do
        begin
          if s[r] in ['a'..'z'] then begin ar:=ord(s[r])-ord('a')+1;inc(temp);end
          else if s[r] in ['A'..'Z'] then begin ar:=ord(s[r])-ord('A')+1;inc(temp);end
          else inc(r);
        end;
        if al=ar then begin
        if ans<(temp) THEN
        begin ANS:=temp; nowr:=r; nowl:=l; end;end
        else bo:=false;
      end;
      dec(l); inc(r);
      if (l<1) or (r>n) then bo:=false;
    until bo=false;
  end;
  writeln(ans);
  
  {output}
  for i:=nowl to nowr do
  begin
  write(s[i]);
  if huanhang[i] then writeln;
  end;
  if huanhang[nowr] = false then writeln;
  closef;
end.
View Code

1.3.4  Prime Cryptarithm

     直接模拟牛式的计算过程,然后判断是否可行,判断可以用集合(set),看计算出的数字是否在集合内。

{ID: jiangyi10
PROG:crypt1
LANG: PASCAL
}
var
  se:set of 1..9;
  a:array[1..9] of longint;
  ans,a1,a2,a3,a4,x,a5,i,j,k,l,n:longint;
  s1,s5:array[1..4] of longint;
  s2:array[1..2] of longint;
  s3,s4:array[1..3] of longint;
  bo:boolean;

{file}
procedure openf;
begin
  assign(input,'crypt1.in'); reset(input);
  assign(output,'crypt1.out'); rewrite(output);
end;
procedure closef;
begin
  close(input); close(output);
  halt;
end;

begin
  {input}
  openf;
  readln(n);
  se:=[];
  for i:=1 to n do
  begin
    read(a[i]);
    se:=se+[a[i]];
  end;
  
  {doit}
  for a1:=1 to n do
    for a2:=1 to n do
      for a3:=1 to n do
        for a4:=1 to n do
          for a5:=1 to n do
          begin
            s1[1]:=a[a1]; s1[2]:=a[a2];
            s1[3]:=a[a3]; s2[1]:=a[a4];
            s2[2]:=a[a5];
            if (s2[1]*s1[1]>=10)or(s2[2]*s1[1]>=10) then continue
            else if(s2[1]*s1[1]+(s2[1]*s1[2])div 10>=10)or(s2[2]*s1[1]+(s2[2]*s1[2])div 10>=10)then continue
            else begin
              bo:=true;
              x:=0;
              s3[3]:=s1[3]*s2[2];
              x:=s3[3] div 10;
              s3[3]:=s3[3] mod 10;
              s3[2]:=s1[2]*s2[2]+x;
              x:=s3[2] div 10;
              s3[2]:=s3[2] mod 10;
              s3[1]:=s1[1]*s2[2]+x;
              x:=0;
              s4[3]:=s1[3]*s2[1];
              x:=s4[3] div 10;
              s4[3]:=s4[3] mod 10;
              s4[2]:=s1[2]*s2[1]+x;
              x:=s4[2] div 10;
              s4[2]:=s4[2] mod 10;
              s4[1]:=s1[1]*s2[1]+x;
              x:=0;
              s5[4]:=s3[3];
              s5[3]:=s3[2]+s4[3];
              x:=s5[3] div 10;
              s5[3]:=s5[3] mod 10;
              s5[2]:=s3[1]+s4[2]+x;
              x:=s5[2] div 10;
              s5[2]:=s5[2] mod 10;
              s5[1]:=s4[1]+x;
              for i:=1 to 3 do
              begin
                if(not (s3[i]  in se)) then bo:=false;
                if(not (s4[i]  in se)) then bo:=false;
                if(not (s5[i]  in se)) then bo:=false;
              end;
              if not(s5[4] in se) then bo:=false;
              if bo then inc(ans);
            end;
          end;
  
  {output}
  writeln(ans);
  closef;
end.
View Code

 

 1.4.1  Packing Rectangles

      一年前不会,现在依然没有思路,的的确确是模拟但就是分不清情况,只好先跳过,真伤心。

1.4.2  The Clocks

      将钟的时间抽象为0,1,2,3,直接顺序枚举,加上操作产生值并对4取模,发现所有钟的值为0则方案可行,但是注意每一个指令最多只能执行3次,4次等于没执行,当发现有种方案可行就直接输出,因为是顺序枚举,所以一定是字典序最小的。

{ID: jiangyi10
PROG:clocks
LANG: PASCAL
}
const
  a1:array[1..9,0..5] of longint=((4,1,2,4,5,0),
  (3,1,2,3,0,0),(4,2,3,5,6,0),(3,1,4,7,0,0),(5,2,4,5,6,8),
  (3,3,6,9,0,0),(4,4,5,7,8,0),(3,7,8,9,0,0),(4,5,6,8,9,0));
var
  bo:boolean;
  i,j,k,l,m,n:longint;
  a,c,q:array[1..9] of longint;
  b:array[1..9] of longint;
  q1,q2,q3,q4,q5,q6,q7,q8,q9:longint;
  
{file}
procedure openf;
begin
  assign(input,'clocks.in'); reset(input);
  assign(output,'clocks.out'); rewrite(output);
end;
procedure closef;
begin
  close(input); close(output);
  halt;
end;

begin
  {input}
  openf;
  for i:=1 to 9 do
  begin
    read(k);
    if k=3 then a[i]:=1
    else if k=6 then a[i]:=2
    else if k=9 then a[i]:=3
    else a[i]:=4;
  end;
  
  {doit}
  for q1:=0 to 3 do
  for q2:=0 to 3 do
  for q3:=0 to 3 do
  for q4:=0 to 3 do
  for q5:=0 to 3 do
  for q6:=0 to 3 do
  for q7:=0 to 3 do
  for q8:=0 to 3 do
  for q9:=0 to 3 do
  begin
    bo:=true;
    for i:=1 to 9 do
    c[i]:=a[i];
    q[1]:=q1;
    q[2]:=q2;
    q[3]:=q3;
    q[4]:=q4;
    q[5]:=q5;
    q[6]:=q6;
    q[7]:=q7;
    q[8]:=q8;
    q[9]:=q9;
    for i:=1 to 9 do
    while q[i]>0 do
    begin
      for j:=1 to a1[i,0] do
      inc(c[a1[i,j]]);
      dec(q[i]);
    end;
    for i:=1 to 9 do
    if c[i] mod 4 <>0 then bo:=false;
    q[1]:=q1;
    q[2]:=q2;
    q[3]:=q3;
    q[4]:=q4;
    q[5]:=q5;
    q[6]:=q6;
    q[7]:=q7;
    q[8]:=q8;
    q[9]:=q9;
    if bo then
      begin
        if (q[1]<>0) and bo then begin write(1); dec(q[1]); end
        else if (q[2]<>0) and bo then begin write(2); dec(q[2]); end
        else if (q[3]<>0) and bo then begin write(3); dec(q[3]); end
        else if (q[4]<>0) and bo then begin write(4); dec(q[4]); end
        else if (q[5]<>0) and bo then begin write(5); dec(q[5]); end
        else if (q[6]<>0) and bo then begin write(6); dec(q[6]); end
        else if (q[7]<>0) and bo then begin write(7); dec(q[7]); end
        else if (q[8]<>0) and bo then begin write(8); dec(q[8]); end
        else if (q[9]<>0) and bo then begin write(9); dec(q[9]); end;
        for i:=1 to q[1] do write(' ',1);
        if q[2]<>0 then for i:=1 to q2 do write(' ',2);
        if q[3]<>0 then for i:=1 to q3 do write(' ',3);
        if q[4]<>0 then for i:=1 to q4 do write(' ',4);
        if q[5]<>0 then for i:=1 to q5 do write(' ',5);
        if q[6]<>0 then for i:=1 to q6 do write(' ',6);
        if q[7]<>0 then for i:=1 to q7 do write(' ',7);
        if q[8]<>0 then for i:=1 to q8 do write(' ',8);
        if q[9]<>0 then for i:=1 to q9 do write(' ',9);
        writeln;
        closef;
      end;
  end;
end.
View Code

1.4.3  Arithmetic Progressions

      直接暴力枚举每一种情况就可以了,不过需要排序剪枝一下,总的来说没什么技巧性。

{ID: jiangyi10
PROG:ariprog
LANG: PASCAL
}
var
  b:array[0..625000]of boolean;
  a:array[0..500000]of longint;
  p,i,j,k,m,n,tot,l:longint;
  ok,bo:boolean;

{file}
procedure openf;
begin
  assign(input,'ariprog.in'); reset(input);
  assign(output,'ariprog.out'); rewrite(output);
end;
procedure closef;
begin
   close(input);  close(output);
   halt;
end;

{sort}
procedure qsort(l,r:longint);
var
  i,j,t,mid:longint;
begin
  i:=l; j:=r;
  mid:=a[l+random(r-l+1)];
  repeat
    while a[i]<mid do inc(i);
    while a[j]>mid do dec(j);
    if i<=j then begin
      t:=a[i];
      a[i]:=a[j];
      a[j]:=t;
      inc(i); dec(j);
    end;
  until i>j;
  if i<r then qsort(i,r);
  if l<j then qsort(l,j);
end;

{check}
function check(x,y:longint):boolean;
var
  i,m:longint;
begin
  m:=x;
  for i:=1 to n-1 do
  begin
    inc(m,y);
    if not b[m] then exit(false);
  end;
  exit(true);
end;

begin
  {input}
  openf;
  read(n,m);

  {doit}
  for i:=0 to m do
  for j:=i to m do
  begin
    if not b[i*i+j*j] then
    begin
      inc(tot);
      a[tot]:=i*i+j*j;
      b[a[tot]]:=true;
    end;
  end;
  randomize;
  qsort(1,tot);
  l:=2*m*m;
  for i:=1 to 2*m*m div (n-1) do
  begin
    k:=(n-1)*i;
    for j:=1 to tot do
    begin
      if a[j]+k>l then break;
      if check(a[j],i) then begin
        bo:=true;
        writeln(a[j],' ',i);
      end;
    end;
  end;
  if not bo then writeln('NONE');
  closef;
end.
View Code

1.4.4  Mother's Milk

      很纯粹的模拟,对于每一种情况讨论一下,然后深搜求解,对于搜过的情况,用三维数组标记,减少搜索量。

{ID: jiangyi10
PROG:milk3
LANG: PASCAL
}
var
  va,vb,vc,na,nb,nc,i,j,k,l,m,n:longint;
  ans:array[0..20] of boolean;
  v:array[0..20,0..20,0..20] of boolean;

{file}
procedure openf;
begin
  assign(input,'milk3.in'); reset(input);
  assign(output,'milk3.out'); rewrite(output);
end;
procedure closef;
begin
  close(input); close(output);
  halt;
end;

{search}
procedure search(na,nb,nc:longint);
begin
  if v[na,nb,nc] then exit else v[na,nb,nc]:=true;
  if na =0 then ans[nc]:=true;
  if (na>0)and(na+nb>vb) then search(na-(vb-nb),vb,nc);
  if (na>0)and(na+nb<=vb) then search(0,na+nb,nc);
  if (nb>0)and(nb+na>va) then search(va,nb-(va-na),nc);
  if (nb>0)and(nb+na<=va) then search(na+nb,0,nc);
  if (nb>0)and(nb+nc>vc) then search(na,nb-(vc-nc),vc);
  if (nb>0)and(nb+nc<=vc) then search(na,0,nb+nc);
  if (nc>0)and(nc+nb>vb) then search(na,vb,nc-(vb-nb));
  if (nc>0)and(nc+nb<=vb) then search(na,nb+nc,0);
  if (nc>0)and(nc+na>va) then search(va,nb,nc-(va-na));
  if (nc>0)and(nc+na<=va) then search(nc+na,nb,0);
  if (na>0)and(na+nc>vc) then search(na-(vc-nc),nb,vc);
  if (na>0)and(na+nc<=vc) then search(na+nc,nb,0);
end;

begin
  {input}
  openf;
  readln(va,vb,vc);
  
  {doit}
  nc:=vc;
  search(na,nb,nc);
  ans[vc]:=true;
  for i:=0 to 20 do
  if ans[i] then break;
  n:=i; write(i);
  for i:=n+1 to 20 do
  
  {output}
  if ans[i] then write(' ',i);
  writeln;
  closef;
end.
View Code

 

1.5.1  Number Triangles

      简单的模拟,直接由下往上递推,选取下面最大值累加至上一层,最后输出第一层就是答案了。

{ID: jiangyi10
PROG:numtri
LANG: PASCAL
}
var
  i,j,k,l,m,n:longint;
  a:array[0..1005,0..1005] of longint;

{file}
procedure  openf;
begin
  assign(input,'numtri.in'); reset(input);
  assign(output,'numtri.out'); rewrite(output);
end;
procedure closef;
begin
  close(input); close(output);
  halt;
end;

{max}
function max(q,w:longint):longint;
begin
  if q>w then exit(q)
  else exit(w);
end;

begin
  {input}
  openf;
  readln(n);
  for i:=1 to n do
  for j:=1 to i do
  read(a[i,j]);
  
  {doit}
  for i:=n-1 downto 1 do
  for j:=1 to i do
  inc(a[i,j],max(a[i+1,j],a[i+1,j+1]));
  
  {output}
  writeln(a[1,1]);
  closef;
end.
View Code

1.5.2  Prime Palindromes

      先生成范围内的回文数,之后再判断是否是素数即可,有一个神奇的发现,因为是奇数,所以Miller算法只要判断7和61即可全过,不过保险一点还是加上一些随机。

{ID: jiangyi10
PROG:pprime
LANG: PASCAL
}
var
  i,j,k,l:longint;
  w,m,n,ans:int64;

{file}
procedure openf;
begin
  assign(input,'pprime.in'); reset(input);
  assign(output,'pprime.out'); rewrite(output);
end;
procedure closef;
begin
  close(input); close(output);
  halt;
end;

{power}
function power(a,b,m:int64):int64;
var
  y,t:int64;
begin
  t:=1;
  y:=a;
  while b<>0 do
  begin
    if b and 1=1 then t:=(t*y) mod m;
    y:=y*y mod m;
    b:=b shr 1;
  end;
  exit(t);
end;

{miller}
function pan(t:int64):boolean;
var
  i:longint;
begin
  for i:=1 to 8 do begin
  w:=random(t-2)+1;
  if power(w,t-1,t)<>1 then exit(false);
  end;
  if power(2,t-1,t)<>1 then exit(false);
  if power(7,t-1,t)<>1 then exit(false);
  if power(61,t-1,t)<>1 then exit(false);
  exit(true);
end;

begin
  {input}
  openf;
  readln(m,n);
  randomize;

  {special}
  if (m<=5) and (n>=5) then writeln('5');
  if (m<=7) and (n>=7) then writeln('7');
  if (m<=11) and (n>=11) then writeln('11');

  {3}
  for i:=1 to 9 do
  for j:=0 to 9 do
  if odd(i) then
  begin
    ans:=i*100+j*10+i;
    if (ans<m) or (ans>n)then continue;
    if pan(ans) then writeln(ans);
  end;

  {5}
  for i:=1 to 9 do
  for j:=0 to 9 do
  for k:=0 to 9 do
  if odd(i) then
  begin
    ans:=i*10000+j*1000+k*100+j*10+i;
    if (ans<m) or (ans>n) then continue;
    if pan(ans) then writeln(ans);
  end;

  {7}
  for i:=1 to 9 do
  for j:=0 to 9 do
  for k:=0 to 9 do
  for l:=0 to 9 do
  if odd(i) then
  begin
    ans:=i*1000000+j*100000+k*10000+l*1000+k*100+j*10+i;
    if (ans<m) or (ans>n) then continue;
    if pan(ans) then writeln(ans);
  end;
  closef;
end.
View Code

1.5.3  Superprime Rib

      由于每一步都要是质数,所以这个数一定由1,3,7,9组成,所以直接搜索这四个数就可以了,关于素数判定同上题,Miller只要7和61就可以全过。

{ID: jiangyi10
PROG:sprime
LANG: PASCAL
}
const
  a:array[1..4] of longint=(1,3,7,9);
var
  ans,i,j,k,l,m,n:longint;

{file}
procedure openf;
begin
  assign(input,'sprime.in'); reset(input);
  assign(output,'sprime.out'); rewrite(output);
end;
procedure closef;
begin
  close(input); close(output);
  halt;
end;

{power}
function power(a,b,m:int64):int64;
var
  y,t:int64;
begin
  t:=1;
  y:=a;
  while b<>0 do
  begin
    if b and 1=1 then t:=(t*y) mod m;
    y:=y*y mod m;
    b:=b shr 1;
  end;
  exit(t);
end;

{miller}
function pan(t:int64):boolean;
var
  i:longint;
begin
  if power(7,t-1,t)<>1 then exit(false);
  if power(61,t-1,t)<>1 then exit(false);
  exit(true);
end;

{search}
procedure search(m,x:longint);
var
  i,j,k,l:longint;
begin
  if x=n then begin
    writeln(m);
    exit;
  end;
  for i:=1 to 4 do
  begin
    ans:=m*10+a[i];
    if pan(ans) then search(ans,x+1);
  end;
end;

begin
  {input}
  openf;
  readln(n);

  {special}
  if n=1 then begin
    writeln(2);
    writeln(3);
    writeln(5);
    writeln(7);
  end;

  {doit}
  if n>=2 then begin
    search(2,1);
    search(3,1);
    search(5,1);
    search(7,1);
  end;
  closef;
end.
View Code

1.5.4  checker

      对于方案输出,可以直接搜索,像一般的八皇后问题一样,但是对于方案数,这样肯定会超时,所以,要用上位运算来优化,Martrix神牛的方法不管什么时候看都还是那么高级,用了位运算,巧妙地利用了搜索的有序性来加速,比dancinglink快多了。

{ID: jiangyi10
PROG:checker
LANG: PASCAL
}
var
  num,sum,a,x,i,j,k,l,m,n:longint;
  ans:array[1..100] of longint;
  b,c,d:array[-100..1000] of boolean;

{file}
procedure openf;
begin
  assign(input,'checker.in'); reset(input);
  assign(output,'checker.out'); rewrite(output);
end;
procedure closef;
begin
  close(input); close(output);
  halt;
end;

{queen}
procedure queen(row,ld,rd:longint);
var
  pos,p:longint;
begin
  if row<>x then
  begin
    pos:=x and not (row or ld or rd);
    while pos<>0 do
    begin
      p:=pos and -pos;
      pos:=pos-p;
      queen(row+p,(ld+p)shl 1,(rd+p)shr 1);
    end;
  end
  else inc(sum);
end;

{print}
procedure print;
var
  i:longint;
begin
  for i:=1 to n-1 do
  write(ans[i],' ');
  writeln(ans[n]);
  if num=3 then begin
  writeln(sum);
  closef;
  end;
end;

{search}
procedure search(t:longint);
var
  j:longint;
begin
  if t> n then
  begin
    inc(num);
    if num<= 3 then print;
    exit;
  end;
  for j:=1 to n do
  if b[j] and c[t+j] and d[t-j] then
  begin
    ans[t]:=j;
    b[j]:=false;
    c[t+j]:=false;
    d[t-j]:=false;
    search(t+1);
    b[j]:=true;
    c[j+t]:=true;
    d[t-j]:=true;
  end;
end;

begin
  {input}
  openf;
  fillchar(c,sizeof(c),true);
  fillchar(b,sizeof(b),true);
  fillchar(d,sizeof(d),true);
  readln(n);
  x:=((1 shl n)-1);
  
  {doit}
  queen(0,0,0);
  search(1);
end.
View Code
posted @ 2013-11-17 15:52  forever97  阅读(278)  评论(0编辑  收藏  举报