Usaco1.3 我的程序和题解
http://hi.baidu.com/mfs666/blog/item/4cab5ceef2c055fdb2fb9594.html
usaco1.3 貌似主题是贪心和简单搜索
1.3.1
Mixing Milk (milk)
最显著的贪心,先排序(快排),每次都加入最多的价钱最低的牛奶,直到加满
code
{
ID: mfs.dev2
PROG: milk
LANG: PASCAL
}
program milk;
type
p=record
v,a:longint;
end;
var
n,m,i,d,r,t:longint;
o:array[0..5000] of p;
procedure quicksort(s,t:longint);
var
i,j,q:longint;
t1:p;
begin
i:=s; j:=t; q:=o[(i+j) div 2].v;
repeat
while (o[i].v<q) do inc(i);
while (o[j].v>q) do dec(j);
if (i<=j) then begin
t1:=o[i]; o[i]:=o[j]; o[j]:=t1;
inc(i); dec(j);
end;
until i>j;
if (s<j) then quicksort(s,j);
if (i<t) then quicksort(i,t);
end;
begin
assign(input,'milk.in');
assign(output,'milk.out');
reset(input);
rewrite(output);
readln(n,m);
for i:=1 to m do
readln(o[i].v,o[i].a);
quicksort(1,m);
i:=0;
while d<n do begin
inc(i);
inc(d,o[i].a);
inc(r,o[i].v*o[i].a);
end;
t:=d-n;
dec(r,o[i].v*t);
writeln(r);
close(output);
end.
1.3.2
Barn Repair (barn1)
其实也是贪心,还可以DP,我一开始是用搜索,但是搜索过不了第7个点,而且我看不出来到底是怎么回事,搜这个点时会出现类似死循环的症状。。。但是数据规模比它大得多的后两个点都能过。。。
很诡异
贪心是抄的代码,当时没精神自己写了,思路就是先把整个牛栏用一块木板盖住,每次将最长的间隔划开,直到没有间隔或者是板子数达到最大,这样盖住的间隔最小(所有更大的已经划出),这样板子的利用率最高,可以剩下的板子长度就是答案(最小长度)
dp过几天再写
code
1 dfs
{
ID: mfs.dev2
PROG: barn1
LANG: PASCAL
}
program barn1;
var
m,s,c,min,i:integer;
sn,fl:array[0..200] of integer;
t,tt:longint;
procedure quicksort(s,t:longint);
var
i,j,x,t1:integer;
begin
i:=s; j:=t; x:=sn[(i+j) div 2];
repeat
while (sn[i]<x) do inc(i);
while (sn[j]>x) do dec(j);
if (i<=j) then begin
t1:=sn[i]; sn[i]:=sn[j]; sn[j]:=t1;
inc(i); dec(j);
end;
until i>j;
if (s<j) then quicksort(s,j);
if (i<t) then quicksort(i,t);
end;
procedure dfs(l,n,i:integer);
begin
if n>m then
exit;
if l>min then
exit;
if n+c-i<m then
exit;
if i>c then begin
if l<min then
min:=l;
exit;
end;
if i=3 then
t:=3;
{ inc(t);
tt:=i;
if t>12000000 then
exit;}
if fl[i]=0 then
dfs(l+1,n+1,i+1);
dfs(l+sn[i]-sn[i-1],n,i+1);
end;
begin
assign(input,'barn1.in');
assign(output,'barn1.out');
reset(input);rewrite(output);
readln(m,s,c);
for i:=1 to c do
readln(sn[i]);
quicksort(1,c);
for i:=1 to c do
if sn[i]=sn[i-1]+1 then
fl[i]:=1;
min:=20000;
dfs(1,1,2);
writeln(min,' ',t,' ',tt);
{for i:=1 to c do
writeln(sn[i],' ',fl[i]);}
close(output);
end.
2 贪心
{
ID: mfs.dev2
PROG: barn1
LANG: PASCAL
}
var
m,s,c,x,f,e,i,j,len,tot,em:byte;
occ:array[1..200]of boolean;
heap:array[1..200]of byte;
procedure add (len:byte);
var
i:byte;
begin
heap[em]:=len;
i:=em;
while (i<>1) and (heap[i div 2]<len) do
begin
heap[i]:=heap[i div 2];
heap[i div 2]:=len;
i:=i div 2;
end;
while heap[em]<>0 do
inc(em);
end;
//
procedure fix (s:byte);
var
i,j:byte;
begin
i:=s*2;
j:=s*2+1;
if (i>200) or (heap[i]=0) and (heap[j]=0) then
begin
heap[s]:=0;
if s<em then
em:=s;
exit;
end;
if heap[i]<heap[j] then
begin
heap[s]:=heap[j];
fix(j);
end
else
begin
heap[s]:=heap[i];
fix(i);
end;
end;
//
begin
assign(input,'barn1.in');
assign(output,'barn1.out');
reset(input);
rewrite(output);
readln(m,s,c);
for i:=1 to c do
begin
readln(x);
occ[x]:=true;
end;
f:=1;
while not occ[f] do
inc(f);
e:=s;
while not occ[e] do
dec(e);
em:=1;
i:=f+1;
while i<=e-1 do
if not occ[i] then
begin
j:=i+1;
while not occ[j] do
inc(j);
len:=j-i;
add(len);
i:=j+1;
end
else
inc(i);
tot:=e-f+1;
i:=1;
while (heap[1]<>0) and (i<>m) do
begin
dec(tot,heap[1]);
fix(1);
inc(i);
end;
writeln(tot);
close(input);
close(output);
end.
1.3.3
Calf Flac (calfflac)
这个使用的极为朴素的搜索
由于每个回文都有一个对称中心,一段里面每个字符(符合要求的)都可能是对称中心,于是枚举对称中心,向两边检测(忽略不和要求的字符),直到两边不相等(回文结束)或者有任何一边越界,得出最长回文,要分回文的字符数是奇数还是偶数两种情况,所以代码写得比较麻烦,有一段只是初始化不同,但是懒得用循环,于是用了复制粘贴。。。
nocow题解里有些很神的算法,但是没有具体讲解。。。有空去查查
顺便说,这个的测试数据里面有一个是个程序。。。真是什么都有,据某大牛说还有WS题的数据是一个情书(估计也是与字符串处理有关的,呵呵)
code
{
ID: mfs.dev2
PROG: calfflac
LANG: PASCAL
}
program calfflac;
var
s:array[0..20000] of char;
i,j,t,m,a,b,c,l,k1,k2,fl,lk,ma,mb,ff:longint;
function check(x:char):boolean;
var t:longint;
begin
check:=true;
t:=ord(x);
if t<65 then check:=false;
if (t>90) and (t<97) then check:=false;
if t>122 then check:=false;
end;
function jan(x,y:char):boolean;
var t1,t2:integer;
begin
jan:=false;
t1:=ord(x);t2:=ord(y);
if t1=t2 then jan:=true;
if (t1>=97) and (t1-32=t2) then jan:=true;
if (t1<=90) and (t1+32=t2) then jan:=true;
end;
begin
assign(input,'calfflac.in');
assign(output,'calfflac.out');
reset(input);rewrite(output);
l:=0;
while not eof do begin
inc(l);
read(s[l]);
end;
for i:=1 to l do begin
if not check(s[i]) then continue;
k1:=0;k2:=0;t:=1;fl:=1;ff:=0;
while fl=1 do begin
inc(k1);inc(k2);
while not check(s[i+k1]) do begin
if i+k1+1>l then begin ff:=1; fl:=0; break; end;
inc(k1);
end;
while not check(s[i-k2]) do begin
if i-k2<2 then begin ff:=1; fl:=0; break; end;
inc(k2);
end;
if (jan(s[i+k1],s[i-k2])) and (ff=0) then begin
inc(t,2);a:=i+k1;b:=i-k2;
end else
fl:=0;
end;
if t>m then begin
m:=t;ma:=a;mb:=b;
end;
k1:=-1;k2:=0;t:=0;fl:=1;ff:=0;
while fl=1 do begin
inc(k1);inc(k2);
while not check(s[i+k1]) do begin
if i+k1+1>l then begin ff:=1;fl:=0; break; end;
inc(k1);
end;
while not check(s[i-k2]) do begin
if i-k2<2 then begin ff:=1; fl:=0; break; end;
inc(k2);
end;
if (jan(s[i+k1],s[i-k2])) and (ff=0) then begin
inc(t,2);a:=i+k1;b:=i-k2;
end else
fl:=0;
end;
if t>m then begin
m:=t;ma:=a;mb:=b;
end;
end;
writeln(m);
for i:=mb to ma do
write(s[i]);
writeln;
close(output);
end.
1.3.4
Prime Cryptarithm (crypt1)
直接用枚举性质的搜索,时间复杂度O(n^5),但是n最大为9。。。
枚举两个乘数,分别乘出竖式中间的两个部分和最终结果,然后检测这三个东西是否超位数,是否每个数字都在给出的范围中(这个部分用了两次字符串/数,之间的转换实现,没想到更简洁的实现方法)
code
{
ID: mfs.dev2
PROG: crypt1
LANG: PASCAL
}
program crypt1;
var
f:array[0..10] of integer;
s:array[0..500] of integer;
n,a,b,c,d,e,i,j,o,p,k,t,nt,fl,ans:longint;
procedure check(x,y,z:longint);
var
w:string;
l,i,t:integer;
begin
fl:=1;
if (x>999) or (y>999) or (z>9999) then fl:=0;
str(x,w);
l:=length(w);
for i:=1 to l do begin
val(w[i],t);
if f[t]=0 then fl:=0;
end;
str(y,w);
l:=length(w);
for i:=1 to l do begin
val(w[i],t);
if f[t]=0 then fl:=0;
end;
str(z,w);
l:=length(w);
for i:=1 to l do begin
val(w[i],t);
if f[t]=0 then fl:=0;
end;
end;
begin
assign(input,'crypt1.in');
assign(output,'crypt1.out');
reset(input);
rewrite(output);
readln(n);
for i:=1 to n do begin
read(t);
if f[t]=0 then begin
inc(nt);
s[nt]:=t;
end;
f[t]:=1;
end;
ans:=0;fl:=0;
for i:=1 to nt do
for j:=1 to nt do
for o:=1 to nt do
for p:=1 to nt do
for k:=1 to nt do begin
a:=s[i]*100+s[j]*10+s[o];
b:=s[p]*10+s[k];
c:=a*s[p];
d:=a*s[k];
e:=a*b;
check(c,d,e);
if fl=1 then
inc(ans);
end;
writeln(ans);
close(output);
end.

浙公网安备 33010602011771号