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 <bits/stdc++.h>

#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 <ZT> 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<ans[nx][ny] || ans[nx][ny] == -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<ans[nx][ny] || ans[nx][ny] == -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,再見!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM