NOIP2017复赛普及组题解

--原题见洛谷P3954 - P3957 

 

T1成绩

一看就是 A * 0.2 + B * 0.3 + C * 0.5 .

 

复杂度O (1).

 

T2 图书管理员

我们可以发现,输入数据给定了需求码的位数,所以我们可以预处理出10的1-9次幂,

然后在每次询问中我们可以把图数码 % ( 10^k  )  其中k为需求码的位数.

 

复杂度 O(nq).

 

T3棋盘

记忆化宽搜

 

记录状态:

x,y 表示当前坐标;

cost 表示当前的花费;

magic 表示上一步是否用了魔法,如果用了,magic标记为上一步把这个格子变成了什么颜色,否则magic标记为-1;(这个很关键!)

然后,宽搜时我们可以开一个二维数组ans[][]来维护每个格子的Ans,(初始化为INT_MAX)

最后我们输出ans[m][m] 或 -1 作为答案。

 

//具体见文末代码(有注释)

 

T4跳房子

二分答案+DP

显然这个问题单调,所以我们可以二分答案(不知道的自行百度)。

二分答案中我们可以DP作为check,

50分做法:

F[i] 表示 从 1 跳到 i 的最大分数

显然 F[i] = MAX( F[j] ) + s_i, 其中 j 为所有可以跳到 i 的格子。

 

复杂度O(n^2*k),其中 k为二分答案的check次数

但显然过不了(手动滑稽)。

 

100分做法:

在上一个算法的基础上,用单调队列/线段树 优化DP到 O(nlogn)

 

复杂度O(n * logn * k)

 

T3代码:
#include

#define maxm 500

using namespace std;

inline int read(){ // 读入优化(But没用啊QWQ)

int x = 0,f = 1; char c = getchar();

while (c < '0' || c > '9') {if (c == '-') f = -1;c = getchar();}

while (c <='9' && c >='0') {x = x * 10 + c - '0';c = getchar();}

return x * f;

}

int c[maxm+10][maxm+10],n,m; // 记录颜色和矩阵规模

int ans[maxm+10][maxm+10]; //ans数组

struct ZT{int x,y,magic,cost;}; // 状态记录,见上分析

queue Q; // STL队列

int tx[4] = {0,-1,0,1},ty[4] = {-1,0,1,0}; // 坐标增量

bool Try(int x,int y){ // 一个小判断

return x<=m && y <= m && x>=1 && y >= 1;

}

 

 

int main(){

m = read(); n = read(); //读入

for (int i = 1; i <= m; ++i)

  for (int j = 1; j <= m; ++j)

    c[i][j] = -1,ans[i][j] = -1;

for (int i = 1; i <= n; ++i){

  int X = read(),Y = read(),C = read();

  c[X][Y] = C; // 读入颜色

}

 

ZT tmp; tmp.x = 1; tmp.y = 1; tmp.cost = 0; tmp.magic=-1; //第一个状态

Q.push(tmp);

int Ans=-1;

while ( !Q.empty() ){ // 宽搜

  tmp = Q.front();

  if (tmp.x == m && tmp.y == m){ // 走到终点,更新Ans

    if (Ans==-1) Ans = tmp.cost; else Ans = min(Ans,tmp.cost);

  }

   for (int i = 0; i <= 3; ++i){ // 四个方向

    int nx = tmp.x+ tx[i],ny = tmp.y + ty[i];

    if (Try(nx,ny)){ // 在棋盘中

       if (c[nx][ny] != -1){ // 不用魔法

       ZT New;

       New.x = nx;New.y = ny; // 计算坐标

       New.magic = -1; // 标记

       New.cost = (c[tmp.x][tmp.y] == c[nx][ny]) ? tmp.cost : (tmp.cost+1); //计算花费

       if (tmp.magic == c[nx][ny]) --New.cost; // 特判上一步有没有用魔法

       if (New.cost-1)Q.push(New);

       if (ans[nx][ny] == -1) ans[nx][ny] = New.cost;//如果可以更新ans,就更新

       else ans[nx][ny] = min(ans[nx][ny],New.cost);

      }

 

 

    else if (tmp.magic == -1){ // 用魔法,条件:上一步magic标记为-1

      ZT New;//同理可得

      New.x = nx;New.y = ny; //坐标

      New.magic = c[tmp.x][tmp.y]; //颜色标记

      magic New.cost = tmp.cost+2; // 花费

      if (New.cost-1)  Q.push(New);

      if (ans[nx][ny] == -1) ans[nx][ny] = New.cost; // ans的更新和记录

      else ans[nx][ny] = min(ans[nx][ny],New.cost);

      }//

    }//

  }//for循环结束

 

  Q.pop();

}

printf("%d\n",Ans); // 输出

return 0;

}

 


 

顺便啰嗦几句……

NOIP居然考挂了,只有250(说好的300分呢)(手动滑稽)

T1 T2 T3 本来都会,结果T3写挂了(手动滑稽)

 


NOIP2017,再见!

 

转载于:https://www.cnblogs.com/s-r-f/p/7886968.html

你可能感兴趣的:(NOIP2017复赛普及组题解)