usaco第二章我的所有题解和程序(二) usaco 2.2

usaco 2.2.1 Preface Numbering (preface)

这个就是模拟,只要把题意看明白就成了,按照规则生成罗马数字串,统计出现的次数,规模小,不存在复杂度的问题。不过这个题满实用的,原来我就想知道怎么把阿拉伯数字转成罗马数字。。。

code:

{
ID: mfs.dev2
PROG: preface
LANG: PASCAL
}


program preface;

var
r:array['C'..'X'] of longint;
n,i,j:integer;
s:string;
ii:char;
k:string='IVXLCDM';

procedure make(a:integer);
var t,i:integer;

procedure ad(b:string;c:integer);
   var i:integer;
   begin
    for i:=1 to c do
     s:=s+b;
   end;

begin
   s:='';
   t:=a div 1000;
   ad('M',t);
   t:=(a mod 1000) div 100;
   if t=9 then
    ad('CM',1);
   if (t<=3) and (t<>0) then
    ad('C',t);
   if t=4 then
    ad('CD',1);
   if (t>4) and (t<9) then begin
     ad('D',1);
     ad('C',t-5);
    end;
   t:= ((a mod 1000) mod 100) div 10;
   if t=9 then
    ad('XC',1);
   if (t<=3) and (t<>0) then
    ad('X',t);
   if t=4 then
    ad('XL',1);
   if (t>4) and (t<9) then begin
    ad('L',1);
    ad('X',t-5);
   end;
   t:=(((a mod 1000) mod 100) mod 10);
   if t=9 then
    ad('IX',1);
   if (t<>0) and (t<=3) then
    ad('I',t);
   if t=4 then
    ad('IV',1);
   if (t>4) and (t<9) then begin
    ad('V',1);
    ad('I',t-5);
   end;
end;

procedure st(a:string);
var i:integer;
begin
   for i:=1 to length(a) do
    inc(r[a[i]]);
end;

begin
assign(input,'preface.in');
assign(output,'preface.out');
reset(input);rewrite(output);
readln(n);

for i:=1 to n do begin
   make(i);
   st(s);
end;
   for i:=1 to 7 do begin
    ii:=k[i];
   if r[ii]<>0 then
    writeln(ii,' ',r[ii]);
   end;
close(output);
end.

usaco 2.2.2 Subset Sums (subset)

这个是动规,背包问题变形。背包的容量固定(就是所有数字和的一半),要求恰好装满背包,统计方案数。当前状态下,若物品能装入,则方案数为装和不装的和,否则为不装的,方程为

if j<=i then
     f[i,j]:=f[i-j,j-1]+f[i,j-1]
    else
     f[i,j]:=f[i,j-1];

最后要注意其实这个是答案的两倍,因为f[t,n]是所有的组合出的容量等与总容量一半的方案数,但题目要求输出组数,没组有两种方案结合,所以f[t,n] div 2是所求的输出。

{
ID: mfs.dev2
PROG: subset
LANG: PASCAL
}
program subset;

var
i,j,n,t:integer;
f:array[0..391,0..40] of int64;

begin
assign(input,'subset.in');
assign(output,'subset.out');
reset(input);
rewrite(output);
readln(n);
for i:=0 to n do
   f[0,i]:=1;
t:=((1+n)*n) div 4;

if (((1+n)*n) mod 4)<>0 then
f[t,n]:=0
else

for i:=1 to t do
   for j:=1 to n do
    if j<=i then
     f[i,j]:=f[i-j,j-1]+f[i,j-1]
    else
     f[i,j]:=f[i,j-1];

writeln(f[t,n] div 2);
close(output);
end.

usaco 2.2.3 Runaround Numbers (runround)

这个也是模拟,从给出的数字向后枚举,只不过要注意好好读题,把循环数的定义看清楚看全,把判断规则写好写全面。判断过程时间近似常数,所以不会超时。

{
ID: mfs.dev2
PROG: runround
LANG: PASCAL
}

program runround;

var
b,l:longint;
m:string;
fl:array['0'..'9'] of integer;
fln:array[0..9] of integer;

function gl(a:integer):integer;
begin
    gl:=a mod l;
    if gl=0 then
     gl:=l;
end;

function ac:boolean;
var i:integer;
begin
   ac:=true;
   for i:=1 to l do
    if fln[i]=0 then begin
     ac:=false;
     exit;
    end;
end;

function ch(a:string):boolean;
var
   i,n,p,t:integer;
begin
ch:=true;
fillchar(fl,sizeof(fl),0);
if pos('0',a)<>0 then
   begin
    ch:=false;
    exit;
   end;

for i:=1 to l do begin
   if fl[a[i]]=1 then begin
    ch:=false;
    exit;
   end;
   fl[a[i]]:=1;
end;
fillchar(fln,sizeof(fln),0);
p:=1;
fln[1]:=1;
while true do begin
   val(a[p],n);
   t:=p;
   p:=gl(p+n);
   if fln[p]=1 then begin
    if (ac) and (p=1) then
     exit;
    ch:=false;
    exit;
   end;
fln[p]:=1;
end;
end;

begin
assign(input,'runround.in');
assign(output,'runround.out');
reset(input);
rewrite(output);
readln(b);
m:='000';
l:=3;
while not ch(m) do begin
   inc(b);
   str(b,m);
   l:=length(m);
end;

writeln(m);
close(output);

end.

usaco 2.2.4 Party Lamps (lamps)

要理解好题意,属于利用奇偶性的枚举搜索。因为灯只有亮灭两种状态,每个开关的作用其实只有两种,若按了奇数次,灯没有变化,若按了偶数次,则对应的灯的状态将改变。题目给出了4种按钮按的总次数,稍微想想就会发现,4种按钮各按了多少次,按的顺序是什么,其实不影响最终状态,只要他们按的次数的和等与总次数即可,联系前面的奇偶性,可以发现只要枚举每种按钮按的次数是奇数还是偶数,判断是否可以组成总次数(根据奇数加奇数是偶数,偶数加偶数还是偶数),具体判断可以用xor位运算,因为xor刚好符合奇偶数相加的规律。。。时间复杂度o(16),常数。。。

最后的排序可以自己写比较,也可以在前面加1,然后用字符串比较。

code

{
ID: mfs.dev2
PROG: lamps
LANG: PASCAL
}
program lamps;
type v=array[1..101] of integer;

var
i1,i2,i3,i4,a,j,n,mc,rc,o,onc,ofc:integer;
r:array[0..16] of v;
tt:v;
onl,ofl:array[0..101] of integer;
i:array[0..4] of integer;

function gmax(a,b:v):boolean;
var i:integer;
begin

for i:=1 to n do begin
   if b[i]>a[i] then begin
    gmax:=false;
    exit;
   end;
   if a[i]>b[i] then begin
    gmax:=true;
    exit;
   end;
end;
gmax:=false;
end;

procedure cp;
var t,j:integer;
begin
t:=i1;
   t:=t xor i2;
   t:=t xor i3;
   t:=t xor i4;
if (t<>(mc and 1)) or (i1+i2+i3+i4>mc) then
   exit;
inc(rc);
for j:=1 to 100 do
   r[rc][j]:=1;
j:=1;
while (j<=n) and (i2=1) do begin
   r[rc][j]:=r[rc][j] xor 1;
   inc(j,2);
end;
j:=2;
while (j<=n) and (i3=1) do begin
   r[rc][j]:=r[rc][j] xor 1;
   inc(j,2);
end;
j:=1;
while (j<=n) and (i4=1) do begin
   r[rc][j]:=r[rc][j] xor 1;
   inc(j,3);
end;
if i1=1 then
   for j:=1 to n do
    r[rc][j]:=r[rc][j] xor 1;
for j:=1 to onc do
   if r[rc][onl[j]]=0 then begin
    dec(rc);
    exit;
   end;
for j:=1 to ofc do
   if r[rc][ofl[j]]=1 then begin
      dec(rc);
      exit;
   end;
end;

begin
assign(input,'lamps.in');
assign(output,'lamps.out');
reset(input);rewrite(output);
readln(n);
readln(mc);
read(a);
while a<>-1 do begin
inc(onc);
onl[onc]:=a;
read(a);
end;
read(a);
while a<>-1 do begin
inc(ofc);
ofl[ofc]:=a;
read(a);
end;

for i1:=0 to 1 do
for i2:=0 to 1 do
   for i3:=0 to 1 do
    for i4:=0 to 1 do
      cp;
    j:=1;
for j:=1 to rc-1 do
   for o:=j+1 to rc do
    if gmax(r[j],r[o]) then begin
     tt:=r[j];
     r[j]:=r[o];
     r[o]:=tt;
    end;

for j:=1 to rc do begin
   for o:=1 to n do
    write(r[j][o]);
   writeln;
end;
if rc=0 then
   writeln('IMPOSSIBLE');
close(output);
end.

posted @ 2008-12-11 12:29  jesonpeng  阅读(216)  评论(0编辑  收藏  举报