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.