【卖萌向】NOIP提高组 2010解题报告
在推倒NOIP的路上渐行渐远ing …
一入OI深似海……
直接上正文
1.[NOIP2010]机器翻译
小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章。
这 个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义来替换。对于每个英文单词,软件会先在内存中查找这个单词的中文含义,如果 内存中有,软件就会用它进行翻译;如果内存中没有,软件就会在外存中的词典内查找,查出单词的中文含义然后翻译,并将这个单词和译义放入内存,以备后续的 查找和翻译。
假设内存中有M 个单元,每单元能存放一个单词和译义。每当软件将一个新单词存入内存前,如果当前内存中已存入的单词数不超过M−;;1,软件会将新单词存入一个未使用的内存单元;若内存中已存入M 个单词,软件会清空最早进入内存的那个单词,腾出单元来,存放新单词。
假设一篇英语文章的长度为N 个单词。给定这篇待译文章,翻译软件需要去外存查找多少次词典?假设在翻译开始前,内存中没有任何单词。
【数据范围】
对于10%的数据有M=1,N≤ 5。
对于100%的数据有0<M≤ 100,0<N ≤ 1000。
(⊙o⊙)… 人家才不告诉你这是水题呢(卖萌ing)
自信题 开个先进先出的队列 定头尾指针指针 一旦超过M便 头尾指针整体后移……
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 program zixin;
2 var f:array[1..1000] of longint;
3 i,j,k,ans,head,max,n,t,last:longint;
4 function check:boolean;
5 var i:longint;
6 begin
7 check:=false;
8 for i:=head to last do
9 if t=f[i] then exit(true)
10 end;
11
12 begin
13
14 read(max,n);
15 head:=1; last:=0; ans:=0;
16 for i:=1 to n do
17 begin
18 read(t);
19 if check=false then
20 begin
21 if last-head=max-1 then
22 begin
23 inc(last);
24 inc(head);
25 f[last]:=t;
26 inc(ans);
27 end
28 else
29 begin
30 inc(last);
31 f[last]:=t;
32 inc(ans);
33 end;
34 end;
35 end;
36 write(ans);
37 end.
2.乌龟棋
四维DP啊四维DP 稍微想下应该(好吧 我看某大神解题报告了…… DP是OI之痛)就A了
动态转移方程
f[b,c,d,e]:=max(f[b-1,c,d,e],f[b,c-1,d,e],f[b,c,d-1,e],f[b,c,d,e-1])+a[b+c*2+d*3+e*4+1];
f[i][j][k][l]表示用去i,j,k,l的一步、二步、三步、四步……6
想出DP方程后就淡定的套代码吧
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 program ttt;
2 var
3 f:array[-1..40,-1..40,-1..40,-1..40]of integer;(动归数组)
4 n,m,b,c,d,e,g,h,i,j:integer;
5 a:array[1..350]of integer;
6 q:array[1..4]of integer;(1~4种卡片的数量)
7 function max(q,w,e,r:integer):integer;
8 begin
9 if q<w then q:=w;
10 if e<r then e:=r;
11 if q<e then max:=e else max:=q;
12 end;
13 begin
14 read(n,m);
15 for i:=1 to n do read(a[i]);
16 fillchar(q,sizeof(q),0);
17 for b:=1 to m do
18 begin
19 read(c);
20 inc(q[c]);
21 end;
22 fillchar(f,sizeof(f),0);
23 f[0,0,0,0]:=a[1];(dp)
24 for b:=0 to q[1] do
25 for c:= 0 to q[2] do
26 for d:= 0 to q[3] do
27 for e:= 0 to q[4] do
28 f[b,c,d,e]:=max(f[b-1,c,d,e],f[b,c-1,d,e],f[b,c,d-1,e],f[b,c,d,e-1])+a[b+c*2+d*3+e*4+1];
29 write(f[q[1],q[2],q[3],q[4]]);
30 end.
3.
3.关押罪犯
S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N。他们之间的关系自然也极不和谐。很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突。我们用“怨气值”(一个正整 数值)来表示某两名罪犯之间的仇恨程度,怨气值越大,则这两名罪犯之间的积怨越多。如果两名怨气值为c 的罪犯被关押在同一监狱,他们俩之间会发生摩擦,并造成影响力为c 的冲突事件。
每年年末,警察局会将本年内监狱中的所有冲突事件按影响力从大到小排成一个列表,然后上报到S 城Z 市长那里。公务繁忙的Z 市长只会去看列表中的第一个事件的影响力,如果影响很坏,他就会考虑撤换警察局长。
在 详细考察了N 名罪犯间的矛盾关系后,警察局长觉得压力巨大。他准备将罪犯们在两座监狱内重新分配,以求产生的冲突事件影响力都较小,从而保住自己的乌纱帽。假设只要处 于同一监狱内的某两个罪犯间有仇恨,那么他们一定会在每年的某个时候发生摩擦。那么,应如何分配罪犯,才能使Z 市长看到的那个冲突事件的影响力最小?这个最小值是多少?
输入格式
输入文件的每行中两个数之间用一个空格隔开。
第一行为两个正整数N 和M,分别表示罪犯的数目以及存在仇恨的罪犯对数。
接下来的M 行每行为三个正整数aj,bj,cj,表示aj 号和bj 号罪犯之间存在仇恨,其怨
气值为cj。数据保证1<aj=<=bj<=N ,0 < cj≤ 1,000,000,000,且每对罪犯组合只出现一
次。
输出格式
共1 行,为Z 市长看到的那个冲突事件的影响力。如果本年内监狱中未发生任何冲突事件,请输出0。
很关键的一题 如果A了基本省一就到手了……
有两种方法
1.二分图匹配(没去写,基本思想听陈强讲了下……)好理解但程序长(谢老师语)
2.并查+快排+贪心 (难理解但程序相当简练)想清楚了就是一种逻辑关系 A不和B在一起 A不和C在一起 那么 b和c肯定在一起我一直认为能在考场上想出第二种作法的人基本都是省队级别了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 program jy;
2 type line=record
3 x,y,d:longint;
4 end;
5 var f:array[0..20000] of longint;
6 h:array[0..20000] of longint;(表示i的敌人是h[I] 大牛的神思路后面会解释)
7 map:array[0..100000] of line;
8 n,m,tx,ty,i:longint;
9
10 procedure qsort(l,r:longint);
11 var
12 i,j,mid:longint;
13 t:line;
14 begin
15 i:=l;
16 j:=r;
17 mid:=map[(l+r) div 2].d;
18 repeat
19 while map[i].d>mid do inc(i);
20 while map[j].d<mid do dec(j);
21 if i<=j then
22 begin
23 t:=map[i];
24 map[i]:=map[j];
25 map[j]:=t;
26 inc(i);
27 dec(j);
28 end;
29 until i>j;
30 if i<r then qsort(i,r);
31 if l<j then qsort(l,j);
32 end;
33 function get(t:longint):longint;
34 begin
35 if f[t]=t then exit(t);
36 f[t]:=get(f[t]);
37 exit(f[t]);
38 end;
39 procedure together(t1,t2:longint);
40 var xx,yy:longint;
41 begin
42 xx:=get(t1);
43 yy:=get(t2);
44 if xx<>yy then f[xx]:=yy;
45 end;
46
47
48
49
50
51
52
53
54
55
56
57 begin
58
59 readln(n,m);
60 for i:=1 to m do
61 readln(map[i].x,map[i].y,map[i].d);
62 for i:=1 to n do
63 f[i]:=i;
64 qsort(1,m);
65
66 for i:=1 to m do
67 begin
68 tx:=get(map[i].x);{x的父节点}
69 ty:=get(map[i].y);{y的父节点}
70 if tx=ty then(发生冲突 即当前处理的边的权值就是答案!)
71 begin
72 writeln(map[i].d);
73 halt;
74 end;
75 if (h[map[i].x]=0) and (h[map[i].y]=0) then(若两人无敌人 则互为敌人)
76 begin
77 h[map[i].x]:=map[i].y;
78 h[map[i].y]:=map[i].x;
79 continue;
80 end;
81 if h[map[i].x]=0 then(若其中一人有敌人 则让无敌人的那个把他当敌人)
82 h[map[i].x]:=map[i].y;
83 if h[map[i].y]=0 then
84 h[map[i].y]:=map[i].x;
85 together(h[map[i].x],map[i].y);(合并之)
86 together(h[map[i].y],map[i].x);
87 end;
88 write('0');
89 end.
ps H数组可以说是抽象的墙
例 H[1]=2 即1与2阴阳相隔那个阴阳相隔
4.[NOIP2010]引水入城
在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠。该国的行政区划十分特殊,刚好构成一个N 行M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城市都有一个海拔高度。
为了使居民们都尽可能饮用到清澈的湖水,现在要在某些城市建造水利设施。水利设施有两种,分别为蓄水厂和输水站。蓄水厂的功能是利用水泵将湖泊中的水抽取到所在城市的蓄水池中。因此,只有与湖泊毗邻的第1 行的城市可以建造蓄水厂。而输水站的功能则是通过输水管线利用高度落差,将湖水从高处向低处输送。故一座城市能建造输水站的前提,是存在比它海拔更高且拥有公共边的相邻城市,已经建有水利设施。
由于第N 行的城市靠近沙漠,是该国的干旱区,所以要求其中的每座城市都建有水利设施。那么,这个要求能否满足呢?如果能,请计算最少建造几个蓄水厂;如果不能,求干旱区中不可能建有水利设施的城市数目。
输入格式
输入文件的每行中两个数之间用一个空格隔开。
输入的第一行是两个正整数N 和M,表示矩形的规模。
接下来N 行,每行M 个正整数,依次代表每座城市的海拔高度。
输出格式
输出有两行。如果能满足要求,输出的第一行是整数1,第二行是一个整数,代表最少
建造几个蓄水厂;如果不能满足要求,输出的第一行是整数0,第二行是一个整数,代表有
几座干旱区中的城市不可能建有水利设施。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 {$m 10000000}(编译开关 防爆破用)
2 program water;
3 type ca=record
4 l:longint;
5 r:longint;
6 end;
7 var a:array[0..500,0..501] of longint;
8 bo,bos:array[0..500,0..501] of boolean;
9 t1:array[1..4] of longint=(0,-1,0,1);
10 t2:array[1..4] of longint=(1,0,-1,0);
11 f:array[0..501,0..501] of ca;
12 dp:array[-1..500] of longint;
13 i,j,k,n,m,mint,maxt,ha:longint;
14 stop:ca;
15 procedure go(x,y:longint);(我会告诉你这是用来骗前三个数据的吗……)
16 var i:longint;
17 begin
18 if (x<1)or(x>n)or(y<1)or(y>m)or bos[x,y] then exit;
19 bos[x,y]:=true;
20 for i:=1 to 4 do
21 if a[x,y]>a[x+t1[i],y+t2[i]] then go(x+t1[i],y+t2[i])
22 end;
23 function max(x,y:longint):longint;
24 begin
25 if x>y then exit(x)
26 else exit(y);
27 end;
28 function min(x,y:longint):longint;
29 begin
30 if x<y then exit(x)
31 else exit(y);
32 end;
33 procedure init;
34 begin
35
36 read(n,m);
37 stop.l:=m+1; stop.r:=1;(注意 最后跑得时候这东西打反了 结果磨了一小时)
38 for i:=1 to n do
39 for j:=1 to m do
40 begin
41 read(a[i,j]);
42 f[i,j]:=stop;
43 end;
44
45 for j:=1 to m do
46 begin
47 f[n,j].l:=j;
48 f[n,j].r:=j;
49 end;
50
51 fillchar(dp,sizeof(dp),63);
52 end;
53 procedure sp;
54 begin
55 writeln('0');
56 writeln(mint);
57 halt;
58 end;
59
60
61
62 function bool(x,y:longint):ca;(CLQ的淹洪水+记忆化搜索)
63 var t:ca; i:longint;
64 begin
65 if (x<1)or(x>n)or(y<1)or(y>m) then exit(stop);
66 if bo[x,y] then exit(f[x,y]);(如果x,y这点可以到淹最后一行的l~r 那么可以到达此点的也肯定可以淹到l~r)
67 bo[x,y]:=true;
68 for i:=1 to 4 do
69 if a[x,y]>a[x+t1[i],y+t2[i]] then
70 begin
71 t:=bool(x+t1[i],y+t2[i]);
72 f[x,y].l:=min(f[x,y].l,t.l);
73 f[x,y].r:=max(f[x,y].r,t.r);
74 end;
75 exit(f[x,y]);
76 end;
77 procedure swap(a,b:longint);var t:longint;begin t:=a;a:=b;b:=t;end;
78
79
80
81
82 begin
83
84 init;
85
86 fillchar(bos,sizeof(bos),false);
87 for i:=1 to m do
88 go(1,i);
89 for i:=1 to m do
90 if bos[n,i]=false then inc(mint);
91 if mint>0 then sp;
92 fillchar(bo,sizeof(bo),false);
93 for i:=1 to m do
94 if bo[1,i]=false then bool(1,i);
95 for i:=1 to m-1 do
96 for j:=i+1 to m do
97 if f[1,j].l<f[1,i].l then begin
98 swap(f[1,i].l,f[1,j].l);
99 swap(f[1,i].r,f[1,j].r);
100 end;
101 dp[0]:=0;(最后的DP出结果)
102 for i:=1 to m do
103 for j:=1 to m do
104 if (f[1,j].l<=i)and(i<=f[1,j].r) then dp[i]:=min(dp[i],dp[f[1,j].l-1]+1);
105 writeln(1);
106 writeln(dp[m]);
107
108 end.
PS 我一直认为这一届的出题老师有良心啊