一句话题解:
1 crack: 多关键字快排
2 contact: MST
3 charge: 树形动态规划,泛化物品
4 switch: 搜索题(穷举题)
1 crack
典型初赛第一题,当时比赛没有认真做,果然只拿10分样例分
其实就是多关键字快排,字典序的综合应用了
[cc lang="pascal"]const
table:array['a'..'z'] of longint=(4,2,5,6,1,4,5,6,7,2,3,4,8,9,3,1,2,6,8,9,2,6,3,2,5,7);
maxn=50000;
type
node=record
value:longint;
w:string;
end;
var
w:array[1..maxn] of node;
n,m:longint;
procedure convert(var value:longint;s:string);
var
i:longint;
begin
value:=0;
for i:=1 to length(s) do
inc(value,table[s[i]]);
end;
procedure Init;
var
i:longint;
begin
readln(n,m);
for i:=1 to n do
begin
readln(w[i].w);
convert(w[i].value,w[i].w);
end;
end;
function isMin(a,b:string):boolean;
var
i:longint;
begin
if length(a)length(b)
then exit(false);
for i:=1 to length(a) do
if a[i]b[i]
then exit(false);
exit(false);
end;
procedure qsort(l,r:longint);
var
i,j:longint;
k,t:node;
begin
i:=l;j:=r;k:=w[(i+j) shr 1];
repeat
while (w[i].valuek.value)or((w[j].value=k.value)and(isMin(k.w,w[j].w))) do dec(j);
if ij;
if il then qsort(l,j);
end;
procedure Outit;
var
i:longint;
begin
for i:=n downto n-m+1 do
writeln(w[i].w,' ',w[i].value);
end;
begin
assign(input,'crack.in');reset(input);
assign(output,'crack.out');rewrite(output);
Init;
qsort(1,n);
Outit;
close(input);close(output);
end.
[/cc]
2 contact
当时比赛的时候还没有看过图论的知识,果然不会做
其实就是kruskal或者prim,但我用了比较麻烦的方法将邻接矩阵转为边集数组,再来kruskal,显然代码就爆长了.
值得注意的是,并查集要将父亲合并,当初在这里卡了很久......
[cc lang="pascal"]const
maxn=1000;
type
node=record
u,v,cost:longint;
end;
var
g:array[1..maxn,1..maxn] of longint;
edge,op:array[1..maxn*maxn*2] of node;
father:array[1..maxn] of longint;
m,n,ans,edgeCount,open:longint;
function find(x:longint):longint;
begin
if father[x]x
then father[x]:=find(father[x]);
exit(father[x]);
end;
procedure union(u,v:longint);
begin
father[u]:=v;
end;
procedure Init;
var
i,j,u,v,legal:longint;
begin
readln(n);inc(n);
for i:=1 to n do
begin
for j:=1 to n do
read(g[i,j]);
readln;
end;
for i:=1 to n do
g[i,i]:=1 shr 30;
for i:=1 to n do father[i]:=i;
readln(m);legal:=0;
for i:=1 to m do
begin
readln(u,v);
g[u,v]:=0;
g[v,u]:=0;
if find(v)find(u) then
begin
inc(legal);
union(find(v),find(u));
end;
end;
edgeCount:=0;m:=legal;
for i:=1 to n do
for j:=i to n do
if ij then
begin
inc(edgeCount);
edge[edgeCount].u:=i;
edge[edgeCount].v:=j;
edge[edgeCount].cost:=g[i,j];
end;
end;
procedure qsort(l,r:longint);
var
i,j,k:longint;
t:node;
begin
i:=l;j:=r;k:=edge[(i+j) shr 1].cost;
repeat
while edge[i].costk do dec(j);
if ij;
if il then qsort(l,j);
end;
procedure relax(u,v:longint);
begin
inc(open);
op[open].u:=u;
op[open].v:=v;
end;
procedure kruskal;
var
i,count:longint;
begin
ans:=0;count:=0;open:=0;
qsort(1,edgeCount);
for i:=1 to edgeCount do
begin
if count=n-1-m then break;
if find(edge[i].u)find(edge[i].v) then
begin
inc(count);inc(ans,edge[i].cost);
union(find(edge[i].u),find(edge[i].v));
relax(edge[i].u,edge[i].v);
end;
end;
end;
procedure Outit;
var
i:longint;
begin
writeln(ans);
for i:=1 to open do
writeln(op[i].u,' ',op[i].v);
end;
begin
assign(input,'contact.in');reset(input);
assign(output,'contact.out');rewrite(output);
Init;
kruskal;
Outit;
reset(input);reset(output);
end.[/cc]
3 charge
个人觉得最难的一道题,树形DP一直都不太懂
这道题就是选课变形(出题人如此说),是一棵前优先树(从别人那里看回来的,就是选儿子必选父亲),我们可以在每次DFS儿子之前将父亲的值强行加入到儿子身上,然后再选择取或不取就是了
[cc lang="pascal"]const
trutle=40000000;
maxn=10000;maxc=500;
var
ch:array[0..maxn,0..maxC*2] of longint;
f:array[0..maxn,0..maxc] of longint;
weight:array[1..maxn] of longint;
n,C,ans,i:longint;
procedure Init;
var
i,father:longint;
begin
readln(n,C);
fillchar(ch,sizeof(ch),0);
for i:=1 to n do
begin
readln(father,weight[i]);
inc(ch[father,0]);
ch[father,ch[father,0]]:=i;
end;
fillchar(f,sizeof(f),0);
end;
function whoMax(a,b:longint):longint;
begin
if a>b then exit(a) else exit(b);
end;
procedure dfs(k,C:longint);
var
i,j,child:longint;
begin
if C<=0 then exit;
for i:=1 to ch[k,0] do
begin
child:=ch[k,i];
for j:=0 to C do
f[child,j]:=f[k,j]+weight[child];
dfs(child,C-1);
for j:=1 to C do
f[k,j]:=whoMax(f[k,j],f[child,j-1]);
end;
end;
begin
assign(input,'charge.in'
;reset(input);
assign(output,'charge.out'
;rewrite(output);
Init;
f[0,1]:=trutle;
dfs(0,C);
ans:=-(1 shl 30);
for i:=0 to C do
ans:=whoMax(f[0,i],ans);
writeln(ans);
close(input);close(output);
end.[/cc]
4 switch
我坦诚地说,我是照着标程打的,没想到穷举打表都能那么优雅
因为每种操作就做两次,所以就直接从$0660出发,枚举,然后记录下当前操作步骤,最后打表输出就可以了
通过这道题学到了不少新搜索技巧
这题就不贴代码了,代码插件太垃圾了
感谢这次贴吧提供了一个那么好的长自信的比赛...希望复赛的题目和这个相当难度吧
距离2010NOIP初赛还有28天
距离2010NOIP复赛还有63天
顺带说说blog.cd,实在是不怎么好用,yo2你快点回来吧......