1. 程式人生 > >NOIP2017模擬賽(10) 總結

NOIP2017模擬賽(10) 總結

前言:第三題出奇的難,第二題讓我覺得出奇的不可做。。。

a 機密資訊

題目描述

FJ有個很奇怪的習慣,他把他所有的機密資訊都存放在一個叫機密盤的磁碟分割槽裡,然而這個機密盤中卻沒有一個檔案,那他是怎麼存放資訊呢?聰明的你一定想到了,FJ的資訊都是以資料夾名稱的形式儲存的。FJ給機密盤中的每一個資料夾都編了號,而FJ的機密資訊是由S資料夾轉到T資料夾的過程中必須經過的資料夾名稱組合而成的,由於FJ的磁碟很慢,開啟每個資料夾所耗費的時間等於該資料夾內下一級資料夾的數量。這次的任務是,給出每個資料夾的編號、名稱以及它的父目錄的編號和隱藏了FJ機密資訊的起始資料夾編號和終點資料夾編號,你要計算出來的是FJ機密資訊的長度以及尋找這個機密資訊所需要的總時間。假設你一開始就在起始資料夾位置,此時耗費的時間為0;你每開啟一個資料夾,能夠知道的資料夾名除了當前這個資料夾名之外,還有該資料夾內下一級的資料夾名。

輸入格式

輸入檔案的第一行為3個整數n、s、t,分別代表資料夾的個數、起始資料夾編號、終點資料夾編號,接下來n行,每行有2個整數i、pi和一個長度不超過255的字串si(不包含空格),用空格分開,pi是i號資料夾的父目錄編號(為0時表示該資料夾為根目錄下的一級資料夾),si是i號資料夾的名稱。

輸出格式

輸出檔案共2行,第一行是FJ的機密資訊的長度,第二行是所消耗的時間。

輸入樣例

6 1 5
1 2 Lo
2 3 ra
3 0 .
4 3 bi
5 4 t
6 5 .COM

輸出樣例

8
4

3<=n<=10000,1<=i<=n,0<=pi<=n,保證一定有解。

這裡寫圖片描述

解題思路(LCA)

本題又是一題送分題,但不少人沒理解題目,變成了送命題。
很容易發現我們只要隨便搜尋或模擬一下就可以出解了。然而考場上的naive的我一開始以為是多組資料,然後就寫了個倍增求LCA,後面就懶得改了,實際上只有一組資料,這樣更慢,不如其他人直接一步一步模擬LCA。
然後這麼水的題目有什麼坑點呢?

題目意思說得很不清楚,導致很多人被坑。
①s資料夾已經打開了,不算它的時間。
②從下面開啟t,是要算t的時間的,否則不算。

程式碼

#include <iostream>
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> #define N 10010 using namespace std; int n, s, t, cur = -1, head_p[N], q[N], dep[N], f[20][N]; int C[N], child[N], path[N]; struct Tadj{int next, obj;} Edg[N]; char ch[300]; void Insert(int a, int b){ cur ++; Edg[cur].next = head_p[a]; Edg[cur].obj = b; head_p[a] = cur; } void ycl(){ int head = 0, tail = 0; q[0] = 0; dep[0] = 1; f[0][0] = 0; while(head <= tail){ int now = q[head++]; for(int i = head_p[now]; ~ i; i = Edg[i].next){ int v = Edg[i].obj; q[++tail] = v; f[0][v] = now; dep[v] = dep[now] + 1; child[v] += child[now]; path[v] += path[now]; } } for(int i = 1; i <= 18; i++) for(int j = 0; j <= n; j++) f[i][j] = f[i-1][f[i-1][j]]; } int LCA(int x, int y){ if(dep[x] > dep[y]) swap(x, y); for(int i = 18; i >= 0; i--) if(dep[f[i][y]] >= dep[x]) y = f[i][y]; if(x == y) return x; for(int i = 18; i >= 0; i--) if(f[i][x] != f[i][y]){ x = f[i][x]; y = f[i][y]; } return f[0][x]; } int main(){ freopen("a.in", "r", stdin); freopen("a.out", "w", stdout); scanf("%d%d%d", &n, &s, &t); for(int i = 0; i <= n; i++) head_p[i] = -1; int a, b, c; for(int i = 1; i <= n; i++){ scanf("%d%d%s", &a, &b, &ch); c = strlen(ch); path[a] = c; child[b] ++; C[b] ++; Insert(b, a); } ycl(); int stop = LCA(s, t), temp = (stop == t) ? t : f[0][t]; int Ans1 = path[s] + path[t] - path[stop] - path[f[0][stop]]; int Ans2 = child[s] + child[temp] - child[stop] - child[f[0][stop]] - C[s]; printf("%d\n%d\n", Ans1, Ans2); return 0; }

b 路由器

題目描述

Farmer John 最近買了些新電腦,它向為奶牛們提供上網的機會,但是上網需要路由器,FJ想盡量少買路由器。FJ 有N個 (1 <= N <= 100,000)(編號為1..N)個農場,由 N-1 條長度是1的邊連線起來,沒有環. FJ 可以決定把路由器放在哪些農場. 每個農場只有長度為 K (0 <= K <= 10)的網線,該農場可以連線到距離小於等於K的路由器. 路由器本身已經可以連線到互連網,可以被放置到任意的農場.
FJ至少要買多少個路由器,才能讓每個農場都能上網?農場想要上網的話,至少要連線到一個包含路由器的農場.

輸入格式

  • 第1行:兩個整數: N 和 K
  • 第 2..N行: 每行兩個整數,表示兩個農場之間有長度為1的邊.

輸出格式

第1行:一個整數,FJ至少需要買多少個路由器.

輸入樣例

8 2
3 6
7 1
1 8
2 4
1 4
4 5
2 6

輸出樣例

2

樣例解釋
有8個農場. 農場3和農場6有長度為1的邊,等等
每個農場的網線最遠只能夠連線到2個單位長度的農場.

解題思路(貪心)

本題我在考場上想了將近2h,最後還是不會。我想這是不是一道dp呢?圖論?二分答案+?yy了好久好久,最後我竟然敗給了一條貪(cao)心(yu)題。

首先,略過考場上我腦抽想得那些亂七八糟的奇怪方法,最後沒有任何用(為什麼我就不曾想過貪心呢?),回到正解貪心。

方法一:
我們發現,每個農場都要上網,這是解題的關鍵。我們先搞出一棵樹,然後從深度最深的做起。因為最深的也要上網,而且它無法通過其後代的路由器來上網,必然是通過其上方的節點來上網。
經觀察發現,必然是在其祖先上放最好,而且放在能放的最遠處最好。因為當前點已經最深,與其共享同一個祖先的點也必然能上網。而越遠,放置路由器的上方的點就有更大可能上網。於是我們簡單證明了貪心的正確性。

於是我們按深度排序,將最深的當前不能上網的點向上跳至最遠的能使其上網的點,然後將網路訊號擴充套件,將能被影響到的點打上標記。然後繼續重複此操作,指導所有點都能上網了為止,同時統計答案。
這個的時間複雜度呢,如果排序用桶排,仍舊無法保證是線性的,理論上最壞是平方級別的(不可能達到),所以這就有點玄學了。因為每次打標記後的點還是可能放路由器,很多點會被重複搜到並重復打標記,所以這不是嚴格的線性了。但實測是能過的,下面有一種更加穩定可靠的方法。

方法二:
直接一遍dfs,並在dfs過程中搞貪心。我們記錄兩個陣列far[]和near[]。far[]代表離當前點root最遠的不能上網的後代(包括自己)離當前點的距離是多少呢?一開始far[root]=0;near[]代表離當前點root最近的安裝了路由器的後代(包括自己)離當前點root的距離是多少呢?一開始near[root]=oo。我們發現這兩個記錄的資訊很有意思,因為我們知道了最有用的路由器的位置和最需要被“拯救”的節點的位置,由於全部要能上網,所以必須要拯救那個節點。此時就可以貪心了。
dfs完後代後,先更新出near,far的值:
near[root] = min(near[root], near[v] + 1);
far[root] = max(far[root], far[v] + 1);
然後如果far[root] + near[root] <= K,代表不用在此點裝路由器就可以使其後代(包括自己)全部上網,那麼far[root] = -1。
如果far[root] == K,代表前面更新不了,而且安裝路由器“迫在眉睫”,於是答案加1,far[root] = -1, near[root] = 0, Ans ++。
每個節點都保證其後代都能上網,更新記錄的資訊,是不是還有點dp的意味呢?這真是種巧妙無比的方法!

最後由於無法保證根節點1能上網,要特判一下(就是說根離最遠的上不了網的點距離不足K,不用急迫的安裝,但是往上已經沒路了,而自己的一些後代和可憐的自己還無法上網),這始這需要判斷一下far[1]是否等於-1就行了。
這樣,只有一次簡單的dfs,維護一些東西,時間複雜度就嚴格的線性了。在Linux下也不會dfs爆棧(辣雞winxp)。
當然,這不是本蒟蒻我想出來的,是一個女同學想出來的。。。。
(我並不知道考試時的我在想些什麼)

程式碼

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 100010
#define oo 1e9

using namespace std;

int n, Ans, K; 
int cur, head_p[N], far[N], near[N];
struct Tadj{int next, obj;} Edg[N<<1];

void Insert(int a, int b){
    cur ++;
    Edg[cur].next = head_p[a];
    Edg[cur].obj = b;
    head_p[a] = cur;
}

void dfs(int root, int fa){
    far[root] = 0;  near[root] = oo;
    for(int i = head_p[root]; ~ i; i = Edg[i].next){
      int v = Edg[i].obj;
      if(v == fa)  continue;
      dfs(v, root);
      far[root] = max(far[root], far[v] + 1);
      near[root] = min(near[root], near[v] + 1);
    }

    if(far[root] + near[root] <= K)  far[root] = -1;
    if(far[root] == K)  far[root] = -1, near[root] = 0, Ans ++;
}


int main(){

    freopen("b.in", "r", stdin);
    freopen("b.out", "w", stdout);

    scanf("%d%d", &n, &K);

    cur = -1;
    for(int i = 1; i <= n; i++)  head_p[i] = -1;

    int a, b;
    for(int i = 1; i < n; i++){
      scanf("%d%d", &a, &b);
      Insert(a, b);
      Insert(b, a);
    }

    dfs(1, 0);
    if(~ far[1])  Ans ++; 

    printf("%d\n", Ans);

    return 0;
}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             

c 骨牌遊戲

題目描述

這裡寫圖片描述
這裡寫圖片描述

解(bao)題(ling)思路【獨立考慮+乘法原理+找規律(數學計數)】

將一個骨牌看成一條邊,共有10個點,構成一幅圖。

就是將圖拆成多個簡單環,每條邊都要用到,求拆分的方案數。

我們考慮統計每個點的度數,如果有一個點的度數為奇數,答案肯定是0。
由於考慮整體不好辦,我們單獨考慮每個點對答案的貢獻。由於構成環,當前點必然與其他點成對消失,畫一下圖,我們發現,每個點的貢獻次數恰好是小於當前點度數的奇數數量,每次貢獻就是奇數的大小,然後由於獨立考慮,互不影響,直接用乘法原理連線方案,統計答案。

這題程式碼很好寫,但獨立考慮每個點和找規律、相乘的部分十分難想。

(龍神的做法)

程式碼

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#define N 50

using namespace std;

typedef long long LL;

int n, nG;
int deg[10];
LL ans;

int main(){

    scanf("%d", &nG);
    while(nG --){
      scanf("%d", &n);
      for(int i = 0; i < 10; i++)  deg[i] = 0;
      int x, y;
      for(int i = 1; i <= n; i++){
        scanf("%d%d", &x, &y);
        deg[x] ++;
        deg[y] ++;
      }
      ans = 1;
      for(int i = 0; i < 10; i++)  if(deg[i] & 1)  ans = 0;
      for(int i = 0; i < 10; i++)
       for(int j = 0; j < (deg[i]>>1); j++)
         ans *= (LL)((j<<1) + 1);
      printf("%lld\n", ans);
    }
    return 0;
}

總結

會做的題一定要拿下,不會做的題一定要儘可能水分。平時積累做題經驗,考試時不要緊張,要迅速進入狀態。

這裡寫圖片描述

夢話要在睡著的時候說,是這個世界的規則。

相關推薦

NOIP2017模擬(10) 總結

前言:第三題出奇的難,第二題讓我覺得出奇的不可做。。。 a 機密資訊 題目描述 FJ有個很奇怪的習慣,他把他所有的機密資訊都存放在一個叫機密盤的磁碟分割槽裡,然而這個機密盤中卻沒有一個檔案,那他是怎麼存放資訊呢?聰明的你一定想到了,FJ的資訊都

沖刺Noip2017模擬8 解題報告——五十嵐芒果醬

.cn 其中 www. tex 我不 closed 必須 std -s 1、鼎紋 【問題描述】 據說鼎紋的 種制造 式是 銅模印出來的,這是我國古代勞動 智慧 的結晶。銅模印過的地 ,會留下深深的印記,經過時間的煉化,洗 練成歷史的遺存。 聰明的古代勞動人民擁有一個 a

NOIP模擬9.17(TYVJ NOIP2017模擬D2)

sin shuf lan nvl get targe gin mar use 3tHTU蹦T黴獻冀9鏈ZPhttp://huiyi.docin.com/sina_6345234044 8mv頓綠誆1叢毯顧5FVhttp://weibo.com/u/5846499302 2戲

高二&高一&初三模擬16總結

fst ref cool col ndt tez www nvl amp 到敲勇淤u囊K智泛28月http://www.zcool.com.cn/collection/ZMTg4MDI3ODg=.html 4G38r餃召4諦tjz4http://www.zcool.com.

清北學堂 NOIP2017模擬越心塞

區別 hellip flag 小孩 姐姐 分鐘 單調棧 輸出 是什麽 連續考了一個星期發現自己真的是手感型選手,成績全靠天意。手感好了碼出200+也沒什麽問題,推出式子並且打出自己都不信的操作也有過。手感差了......就一個呵呵二字。 然後開始是T總讓我們休息了一個星期

2016.5.21【初中部 NOIP提高組】模擬A? 總結

100% 重要 思路 6.5 暴力 麻煩 不難 結果 一個 這次比賽的題目看上去好像不難,但當開始仔細想的時候才發現,並沒有那麽簡單。 T1旅行:剛開始看到k<=4的時候還以為有題可以AC了,不過呢,還是毫無思路。 T3Pty爬山:雨天的尾巴最近打了幾道樹鏈剖分,題目

NOIP2018賽前 模擬心得總結

font 電腦 變量名 定義 心得 代碼 模擬 重寫 文件名 7.25 T3最後在暴力後面加了個騙分操作,變量名忘了定義,CE爆零  -70 總結:寫完代碼一定要編譯一下 7.27 中間電源插頭被我踢掉了。。 打開電腦重寫代碼,情急之下將T2、T3文件名寫反了  -180

模擬01 總結

方法 求一個 判斷 至少 子圖 就會 單獨 問題: 。。 題解 1. 數對子 首先發現兩個數異或起來有奇數個1 的充要條件就是一個數有奇數個1,另一個有偶數個1 (這個性質我竟然沒發現。。。) 然後就轉化為求一堆區間的並中有多少個數二進制有奇數個1,多少個數二進制有偶數個1

ZROI 普及組模擬02總結

自己 深入 splay 二叉 line 出了 .com 自己的 超時 ZROI 普及組模擬賽02總結 先放[網址][http://zhengruioi.com/contest/96] 可能是有一段時間沒有打這種正式的比賽了,今天打的很奇怪。。。 T1 模擬水題 既然是普及組

ZROI提高組模擬05總結

最簡 就是 每一個 mat 調整 但是 至少 長度 方法 ZROI提高組模擬賽05總結 感覺是目前為止最簡單的模擬賽了吧 但是依舊不盡人意。。。 T1 有一半的人在30min前就A掉了 而我花了1h11min 就是一個簡單的背包,我硬是轉化了模型想了好久,生生把一個弱智題變

[NOIP2018模擬10.20A]掛分報告

查詢 不用 ble names != 還記得 就是 roi con 閑扯 先看看了B組,T1 ZROI剛好講過一個性質原根一般很小的,直接枚舉;T2一眼二分然後似乎狀壓 T3沒看 然後上來A組題,T1 flow這名字...網絡流?! T1題面非常的社會主義核心價值觀,看到有

[NOIP2018模擬10.25]瞎搞報告

情況 read 要求 ati 大小 樹狀 ... void 兩個 閑扯 最近有點頹,都修到好晚,早上起來和吔shi一樣難受 忍著困意把題面看完,發現啥也不會,又是一場寫暴力的模擬賽 T1發現似乎可以DP,順手碼了個 T2像個最小瓶頸路板子,但是只做過N^2算法的... T3

一中模擬10.31——世界盃

題意: n n n個球隊,每個球隊有

一中模擬10.30——序列

題意:給出一個長度為 n ( n &lt;

一中模擬10.20&10.27——tree1.0&2.0

Tree1.0 Description 選擇起始點和終點以後,會每次等概率隨機走到一個相鄰的點(不能來回走同一條邊多次),問最後走到終點的期望步數 Solution 統計下子樹內和子樹外的點分別作為起點和終點的貢獻即可 Code #include<bits/st

一中模擬10.27——球

Description 眾所周知AKKing_FB有 n ( n

[NOIP2018模擬10.19]只會暴力報告

閒扯 今天又是暴力滿滿(並不)的一天呢 昨天老師說了分數要正態分佈,今天看起來...不過暴力分很多,雖然我人太傻逼又沒打滿 T1 woc?不是說送分的嗎,看起來又是個樹形DP神題,暴力告辭,鏈上的搞一搞 T2 woc?又是樹 紀中這麼喜歡出圖/樹題的嗎?第一眼暴力dij告辭 T3 woc?又又又是樹

[NOIP2018模擬10.18]自閉報告

閒扯 這一天,菜雞RyeCatcher又想起來了被毒瘤題支配的恐懼 今天比較好玩,還是ljy提醒才發現資料夾裡有題面...不知道外面的人什麼時候才發現 看完了題面,又回到了雅禮啥題也不會寫的感覺 T1 發現操作就是交換兩個數於是寫了個假做法就是不同的數之和;分類討論後文件夾裡突然出現一個大樣例!發現我

備戰Noip2018模擬10(B組)T4 Alpha2 蟲食算

備戰Noip2018模擬賽10(B組) T4 Alpha2蟲食算 題目描述 粗心的小明把墨水潑在了乘法算式上,由於他實在是太弱了,不知道怎麼辦,所以請了巨佬pyz,pyz看了一眼就說,我不僅可以

10月20日備戰Noip2018模擬10 T3 Inte 時間相交問題

10月20日備戰Noip2018模擬賽10 T3 Inte 時間相交問題 題目描述 巨佬cyx寫了一張時間表,她有一段時間學習FFT,有時候研究NTT,有時候學習線性代數,有的時候研究PTSD,