NOIP2017解题报告

来源:互联网 发布:电子相册制作软件 知乎 编辑:程序博客网 时间:2024/05/22 14:36

1、成绩

(score.cpp/c/pas)

 

Time Limit: 1 Sec  Memory Limit: 256 MB

 

算法一:

 

这是一道可以和 A+B Problem 相媲美的题目。

读入三个数后直接输出每个数*对应的百分数之和并去掉小数就行了。

 

时间复杂度:O(1)

空间复杂度:O(1)

 

 
算法一_代码

1. var

2.   a,b,c:longint;

3. begin

4.   assign(input, 'score.in');

5.   assign(output, 'score.out');

6.   reset(input);

7.   rewrite(output);

8.   read(a,b,c);

9.   write(a*0.2+b*0.3+c*0.5:0:0);

10.   close(input);

11.   close(output);

12. end.

 

 

 

 

 

 

 

 

 

 

2、图书管理员

(librarian.cpp/c/pas)

 

Time Limit: 1 Sec  Memory Limit: 256 MB

 

算法一:

 

又是一道送分题。

因为读入的编号都是不超过 10^7 的正整数,所以我们可以直接把编号用longint 读进来。我们知道一个数mod 10可以截出这个数的最后一位,mod 100可以截出最后两位...那么我们可以用这种方法把每个图书编号的最后与需求码相同位数的最后几位截出来,再去和需求码比较,取符合条件的最小值。

 

时间复杂度:O(nm)

空间复杂度:O(1)

 

算法

 

我们还可以用字符串处理这些编号,每次把每个图书编号最后与需求码位数相同的位数截出来,再去和需求码对比。

注意字符串比较大小,先比较长度,再去比较大小。

 

时间复杂度:O(nm)

空间复杂度:O(1)

 

 

算法一_代码:

1. var

2.   len,a,b,z:array[0..1001]of longint;

3.   n,m,i,j,ans:longint;

4. begin

5.   readln(n,m);

6.   for i:=1 to n do read(a[i]);

7.   for i:=1 to m do

8.     begin

9.       readln(len[i],b[i]);

10.       z[i]:=1;

11.       while z[i]<=b[i] do z[i]:=z[i]*10;

12.     end;

13.   for i:=1 to m do

14.     begin

15.       ans:=maxlongint;

16.       for j:=1 to n do

17.         if a[j] mod z[i]=b[i] then

18.           if ans>a[j] then ans:=a[j];

19.       if ans=maxlongint then writeln(-1)

20.         else writeln(ans);

21.     end;

22. end.

 

 

 

 

 

 

 

3、棋盘

(chess.cpp/c/pas)

 

Time Limit: 1 Sec  Memory Limit: 256 MB

算法一:

 

对于 30%的数据

按照题意直接 dfs,用个常量数组表示方向,可以加个小剪枝,当前的代价

如果已经不小于当前最优解就直接退出。

 

时间复杂度:O(路径数)

空间复杂度:O(1)

 

算法二:

 

Dp,只考虑往下或往右。

我们把 0 看成无色,另外两种颜色为 1 2

设状态f[i,j,k]为从当(i,j)的颜色为k时从(1,1)(i,j)的最小代价。

方程:

如果当前(i,j)有颜色,显然不用魔法更优,所以:

f[i,j,a[i,j]]:=min(f[i-1,j,t],f[i,j-1,t])+dis(t,a[i,j]);ta[i,j]相同时dis0,否则为1

如果当前(i,j)无色,根据题意,不能走无色的格子,所以一定要用魔法,所以:

f[i,j,k]:=min(f[i-1,j,a[i-1,j]]+2+dis(k,a[i-1,j]),f[i,j-1,a[i,j-1]]+2+dis(a[i,j-1],k)));

注意:a[i-1,j]a[i,j-1]不能为0dis同上。

 

时间复杂度:O(n^2)

空间复杂度:O(n^2)

 

算法三:

上述算法 95...ccf 卡掉了一个点...

对于100%的数据

我们可以把这个棋盘看成一个图,那么题目就转化成了从(1,1)(n,n)的最短路。

思路同 dp,只是现在成了四个方向,跑个SPFA就行了。

 

时间复杂度:O(kn^2)

空间复杂度:O(kn^2)

 

算法二_代码:

1. uses math;

2. var

3.   f:array[0..101,0..101,1..2]of longint;

4.   a:array[0..101,0..101]of longint;

5.   n,m,i,j,x,y,z,k,ans:longint;

6. function dis(x,y:longint):longint;

7. begin

8.   if x=y then exit(0) else exit(1);

9. end;

10. begin

11.   readln(n,m);

12.   for i:=1 to m do

13.     begin

14.       readln(x,y,z);

15.       inc(z);

16.       a[x,y]:=z;

17.     end;

18.   for i:=0 to n do

19.     for j:=0 to n do

20.       for k:=1 to 2 do

21.         f[i,j,k]:=maxlongint div 3;

22.   f[1,1,a[1,1]]:=0;

23.   for i:=1 to n do

24.     for j:=1 to n do

25.       begin

26.         if (i=1)and(j=1) then continue;

27.         if a[i,j]=0 then

28.           begin

29.             for k:=1 to 2 do

30.               begin

31.                 if a[i-1,j]<>0

32.                  then f[i,j,k]:=min(f[i,j,k],f[i-1,j,a[i-1,j]]+2+dis(a[i-1,j],k));

33.                 if a[i,j-1]<>0

34.                  then f[i,j,k]:=min(f[i,j,k],f[i,j-1,a[i,j-1]]+2+dis(a[i,j-1],k));

35.               end;

36.           end

37.           else

38.             begin

39.               for k:=1 to 2 do

40.                 f[i,j,a[i,j]]:=min(f[i,j,a[i,j]],f[i-1,j,k]+dis(k,a[i,j]));

41.               for k:=1 to 2 do

42.                 f[i,j,a[i,j]]:=min(f[i,j,a[i,j]],f[i,j-1,k]+dis(k,a[i,j]));

43.             end;

44.       end;

45.   ans:=min(f[n,n,1],f[n,n,2]);

46.   if ans=maxlongint div 3 then write(-1) else write(ans);

47. end.

 

算法三_代码:

1. uses math;

2. const

3.   dx:array[1..4]of longint=(0,0,1,-1);

4.   dy:array[1..4]of longint=(1,-1,0,0);

5. type

6.   arr=record

7.   l,r:longint;

8. end;

9. var

10.   a:array[0..101,0..101]of longint;

11.   dis:array[0..101,0..101,1..2]of longint;

12.   b:array[0..101,0..101]of boolean;

13.   f:array[0..500001]of arr;

14.   n,m,i,j,k,l,r,x,y,z,h,t,ans,zz:longint;

15. function diss(x,y:longint):longint;

16. begin

17.   if x<>y then exit(1) else exit(0);

18. end;

19. begin

20.   readln(n,m);

21.   for i:=1 to m do

22.     begin

23.       readln(x,y,z);inc(z);a[x,y]:=z;

24.     end;

25.   for i:=1 to n do

26.     for j:=1 to n do

27.       for k:=1 to 2 do

28.         dis[i,j,k]:=maxlongint >> 1;

29.   f[1].l:=1;f[1].r:=1;

30.   h:=0; t:=1;

31.   dis[1,1,a[1,1]]:=0;

32.   while h<=t do

33.     begin

34.       inc(h);

35.       b[f[h].l,f[h].r]:=false;

36.       for k:=1 to 4 do

37.         begin

38.           l:=f[h].l+dx[k]; r:=f[h].r+dy[k];

39.           if not (l in [1..n]) or not (r in [1..n]) then continue;

40.           if (a[l,r]=0)and(a[f[h].l,f[h].r]=0) then continue;

41.           if a[l,r]=0 then

42.             for zz:=1 to 2 do

43.               begin

44.                 z:=dis[f[h].l,f[h].r,a[f[h].l,f[h].r]]+2+diss(a[f[h].l,f[h].r],zz);

45.                 if z<dis[l,r,zz] then

46.                   begin

47.                     dis[l,r,zz]:=z;

48.                     if not b[l,r] then

49.                       begin

50.                         inc(t);

51.                         f[t].l:=l;f[t].r:=r;

52.                         b[l,r]:=true;

53.                       end;

54.                   end;

55.               end

56.               else

57.                 for zz:=1 to 2 do

58.                   begin

59.                     z:=dis[f[h].l,f[h].r,zz]+diss(a[l,r],zz);

60.                     if z<dis[l,r,a[l,r]] then

61.                       begin

62.                         dis[l,r,a[l,r]]:=z;

63.                         if not b[l,r] then

64.                           begin

65.                             inc(t);

66.                             f[t].l:=l;f[t].r:=r;

67.                             b[l,r]:=true;

68.                           end;

69.                       end;

70.                   end;

71.         end;

72.     end;

73.   ans:=min(dis[n,n,1],dis[n,n,2]);

74.   if ans=maxlongint >> 1 then write(-1) else write(ans);

75. end.





4、跳房子

(jump.cpp/c/pas)

 

Time Limit: 2 Sec  Memory Limit: 256 MB

 

算法一:

 

对于 50%的数据

显然答案具有单调性,那么我们可以用二分答案。

然后对于 check,我们考虑dp来判断得分。

设状态f[i]表示最后一步跳到i的最大的分。

方程:f[i]:=max{f[j]}+s[i];(d-g<=x[i]-x[j]<=d+g)

 

时间复杂度:O(n^2 log x[n])

空间复杂度:O(n)

 

算法二:

 

对于 80%的数据

在算法一的基础上加两个优化。

1.j从后往前枚举,如果当前x[i]-x[j]>rbreak

2.如果当前f[i]已经>=m则直接返回true

 

时间复杂度:O(n^2 log x[n])

空间复杂度:O(n)

 

 
算法三:

 

对于 100%的数据。

从算法一可以看出,因为x[i]是递增的,所以符合条件的f[j]肯定是连续的,也就是说f[j]j的取值范围是个区间,而我们要在这个区间里找个max,用个数据结构维护下就行了。而区间的维护,很自然地就想到了线段树。

 

时间复杂度:O(n log n log x[n])

空间复杂度:O(4n)

可能是 ccf 没想到会有人用线段树做,线段树能过官方数据。

但是我考场上写挂了,调了1h 都没调出来

 

算法四:

 

正解。

用单调队列维护f[j]即可。

因为x[i]是递增的,所以每次符合条件的f[j]的那个区间肯定是往前移动的。每次把比上次多出来符合条件的f[j]加入队列,再把不符合的移出就行了。

最后还要判断一下当前队列的第一个是否符合条件和队列是否为空,因为有可能不能从任何点跳到x[i]

 

时间复杂度:O(n log x[n])

空间复杂度:O(n)

 

算法五:

 

思路同单调队列,只是换了种数据结构——堆。依旧是每次把符合条件的f[j]加入堆,不符合的移出。

时间复杂度:O(n log n log x[n])

空间复杂度:O(n)

 

 

算法二_代码:

1. var

2.   a,x,f:array[0..500001]of longint;

3.   n,m,k,i,j,l,r,mid,ans:longint;

4. function check(ans:longint):boolean;

5. var

6.   i,j,l,r:longint;

7. begin

8.   if ans>=k then l:=1 else l:=k-ans;

9.   r:=k+ans;

10.   for i:=1 to n do

11.     begin

12.       f[i]:=-233333333;

13.       for j:=i-1 downto 0 do

14.         begin

15.           if x[i]-x[j]>r then break;

16.           if (x[i]-x[j]>=l)and(x[i]-x[j]<=r) then

17.             if f[j]<>-233333333 then

18.               if f[j]>f[i] then f[i]:=f[j];

19.         end;

20.       if f[i]<>-233333333 then inc(f[i],a[i]);

21.       if f[i]>=m then exit(true);

22.     end;

23.   exit(false);

24. end;

25. begin

26.   readln(n,k,m);

27.   for i:=1 to n do readln(x[i],a[i]);

28.   ans:=-1;

29.   l:=0;

30.   r:=maxlongint >> 1;

31.   while l<=r do

32.     begin

33.       mid:=(l+r) >> 1;

34.       if check(mid) then begin ans:=mid;r:=mid-1 end

35.         else l:=mid+1;

36.     end;

37.   write(ans);

38. end.

 

 

算法三_代码:

1. uses math;

2. const

3.   p=-233333333;

4. type

5.   tree=record

6.   l,r:longint;

7.   sum:int64;

8. end;

9. var

10.   b,x:array[0..500001]of int64;

11.   f:array[0..500001]of int64;

12.   a:array[0..3000001]of tree;

13.   n,m,k,i,j,ans:longint;

14.   l,r,mid,sum:int64;

15. procedure build(k,l,r:longint);

16. var

17.   mid:longint;

18. begin

19.   a[k].l:=l; a[k].r:=r; a[k].sum:=p;

20.   if l=r then exit;

21.   mid:=(l+r) >> 1;

22.   build(k*2,l,mid);

23.   build(k*2+1,mid+1,r);

24. end;

25. procedure add(k,l,r,x:longint);

26. var

27.   mid:longint;

28. begin

29.   if a[k].l=a[k].r then

30.     if a[k].l=l then

31.       begin

32.         a[k].sum:=x;

33.         exit;

34.       end;

35.   mid:=(a[k].l+a[k].r) >> 1;

36.   if mid>=l then add(k << 1,l,r,x);

37.   if mid<r then add(k << 1+1,l,r,x);

38.   a[k].sum:=max(a[k << 1].sum,a[k << 1+1].sum);

39. end;

40. function query(k,l,r:longint):int64;

41. var

42.   ans,mid:longint;

43. begin

44.   if (a[k].l>=l)and(a[k].r<=r) then exit(a[k].sum);

45.   ans:=p;

46.   mid:=(a[k].l+a[k].r) >> 1;

47.   if mid>=l then ans:=max(ans,query(k << 1,l,r));

48.   if mid<r then ans:=max(ans,query(k << 1+1,l,r));

49.   exit(ans);

50. end;

51. function check(ans:longint):boolean;

52. var

53.   i,j,z,zz:longint;

54.   l,r:int64;

55. begin

56.   if ans>=k then l:=1 else l:=k-ans;

57.   r:=k+ans;

58.   build(1,0,n);

59.   add(1,0,0,0);

60.   z:=0; zz:=-1;

61.   for i:=1 to n do

62.     begin

63.       while x[z]<x[i]-r do inc(z);

64.       while x[zz+1]<=x[i]-l do inc(zz);

65.       if (z<0)or(zz<0)or(z>zz) then continue;

66.       f[i]:=query(1,z,zz);

67.       if f[i]<>p then

68.         begin

69.           inc(f[i],b[i]);

70.           add(1,i,i,f[i]);

71.         end;

72.       if f[i]>=m then exit(true);

73.     end;

74.   exit(false);

75. end;

76. begin

77.   readln(n,k,m);

78.   for i:=1 to n do

79.     begin

80.       readln(x[i],b[i]);

81.       if (b[i]>0)and(sum<=m) then inc(sum,b[i]);

82.     end;

83.   if sum<m then

84.     begin

85.       writeln(-1);

86.       halt;

87.     end;

88.   ans:=-1;

89.   l:=0;

90.   r:=x[n];

91.   while l<=r do

92.     begin

93.       mid:=(l+r) >> 1;

94.       if check(mid) then begin ans:=mid;r:=mid-1 end

95.         else l:=mid+1;

96.     end;

97.   write(ans);

98. end.

 

算法四_代码:

1. var

2.   x,a,q:array[0..500001]of longint;

3.   f:array[0..500001]of int64;

4.   n,m,k,i,l,r,mid,ans:longint;

5. function check(z:longint):boolean;

6. var

7.   zz,h,t,i,j:longint;

8. begin

9.   h:=1;t:=1;

10.   q[1]:=0;

11.   f[0]:=0;

12.   for i:=1 to n do f[i]:=-10000000000;

13.   zz:=0;

14.   for i:=1 to n do

15.     begin

16.       while (x[i]-x[zz]>k+z)and(zz<=i) do inc(zz);

17.       while (zz<i)and(x[i]-x[zz]>=k-z)and(x[i]-x[zz]<=k+z) do

18.         begin

19.           while (f[zz]>f[q[t]])and(h<=t) do dec(t);

20.           inc(t);

21.           q[t]:=zz;

22.           inc(zz);

23.         end;

24.       while (x[i]-x[q[h]]>k+z)and(h<=t) do inc(h);

25.       if (h<=t)and(x[i]-x[q[h]]>=k-z)and(x[i]-x[q[h]]<=k+z) then f[i]:=f[q[h]]+a[i];

26.       if f[i]>=m then exit(true);

27.     end;

28.   exit(false);

29. end;

30. begin

31.   readln(n,k,m);

32.   for i:=1 to n do readln(x[i],a[i]);

33.   l:=0;

34.   r:=100000;

35.   ans:=-1;

36.   while l<=r do

37.     begin

38.       mid:=(l+r) >> 1;

39.       if check(mid) then begin ans:=mid;r:=mid-1 end

40.         else l:=mid+1;

41.     end;

42.   writeln(ans);

43. end.

 

算法五_代码:

1. var

2.   x,a,q:array[0..500001]of longint;

3.   f:array[0..500001]of int64;

4.   n,m,k,i,l,r,mid,ans,len:longint;

5. procedure swap(var x,y:longint);

6. var

7.   t:longint;

8. begin

9.   t:=x;x:=y;y:=t;

10. end;

11. procedure put(x:longint);

12. var

13.   son:longint;

14. begin

15.   inc(len);

16.   q[len]:=x;

17.   son:=len;

18.   while (son<>1)and(f[q[son]]>f[q[son >> 1]]) do

19.     begin

20.       swap(q[son],q[son >> 1]);

21.       son:=son >> 1;

22.     end;

23. end;

24. procedure get;

25. var

26.   fa,son:longint;

27. begin

28.   q[1]:=q[len];

29.   dec(len);

30.   fa:=1;

31.   while (fa << 1 <=len)or(fa << 1 +1<=len) do

32.     begin

33.       if (fa << 1 +1>len)or(f[q[fa << 1 ]]>f[q[fa << 1 +1]]) then son:=fa << 1

34.         else son:=fa << 1 +1;

35.       if f[q[son]]>f[q[fa]] then

36.         begin

37.           swap(q[son],q[fa]);

38.           fa:=son;

39.         end

40.         else break;

41.     end;

42. end;

43. function check(z:longint):boolean;

44. var

45.   zz,i,j,l,r:longint;

46. begin

47.   f[0]:=0;

48.   for i:=1 to n do

49.     begin

50.       q[i]:=0;

51.       f[i]:=-10000000000;

52.     end;

53.   len:=0;

54.   zz:=0;

55.   for i:=1 to n do

56.     begin

57.       while (x[i]-x[zz]>k+z)and(zz<=i) do inc(zz);

58.       while (zz<i)and(x[i]-x[zz]>=k-z)and(x[i]-x[zz]<=k+z) do

59.         begin

60.           put(zz);

61.           inc(zz);

62.         end;

63.       while (x[i]-x[q[1]]>k+z)and(len>0) do get;

64.       if len>0 then f[i]:=f[q[1]]+a[i];

65.       if f[i]>=m then exit(true);

66.     end;

67.   exit(false);

68. end;

69. begin

70.   assign(input,'jump.in');

71.   assign(output,'jump.out');

72.   reset(input);

73.   rewrite(output);

74.   readln(n,k,m);

75.   for i:=1 to n do readln(x[i],a[i]);

76.   l:=0;

77.   r:=x[n];

78.   ans:=-1;

79.   while l<=r do

80.     begin

81.       mid:=(l+r) >> 1;

82.       if check(mid) then begin ans:=mid;r:=mid-1 end

83.         else l:=mid+1;

84.     end;

85.   writeln(ans);

86.   close(input);

87.   close(output);

88. end.

原创粉丝点击