今年難度大了很多,也有很多毒瘤題..
這篇博客嘗試詳盡地解析NOIP2018普及初賽.
題目

答案
先附上答案
單項選擇題
1.C
送分題 其他都是輸入設備
2.D
A: $(269)_{16}=617$
B: $617$
C: $(1151)_{8}=617$
D: $(1001101011)_{2}=619$
3.D
常識性知識
$1GB=1024KB=1024*1024B$
4.A
廣域網-Wide Area Network-WAN
想Wide就可以了
5.B
CCF贊歌,最近幾乎每年都有。
直接拿今年年份減去屆數(2018-24=1984)。
6.A
小學奧數。在歷年的基礎上改了下。每8個字母($ASDFasdf$)一個循環,$81%8=1$,所以為A.
7.A
可以正經推出。但考試的時候如果不知道那可以畫幾個例子,然后帶進去算。算出來A為正確。
注意本題樹根深度記做0.
8.A
基數排序就是桶排序,所以不用比較。
沒聽說過?
B.冒泡和D.插入一定知道吧,都需要對比。C.堆排,堆的數據插入后上浮下沉操作需要比對,所以排除法選A。
9.A
看題目首先排除C和D。
然后時間復雜度一般要考慮最壞所以向上取整(然而我還是錯了)。
10.B
送分。
11.C
分類討論。
如下所示:






12.B
注意空集
13.B
小學奧數,分解質因數$10000=2^4*5^4$,2的倍數有4999個,5的倍數有1999個,除去10(2和5的公倍數)999個,加上10000這一個數,不互質的就是6000個,互質的就是10000-6000=4000個
14.B
狀壓DP常規操作,實在不行模擬也可。
15.B
不用多說,先進先出,棧。
問題求解
1
小學奧數,從③推出丁不去,又從④推出甲去了,然后由①推出沒下雨。
2
分類討論。
1-9中:1個
10-99中:1*8+10=18個
100-999中:(1+18)*8+100=252個
1000-1999中:1+18+252=271個
2000-2018中:2個
總共 1+18+252+271+2=544個
注意最后的2個要加上去,我是不會說我沒加的。
閱讀程序寫結果
1
#include <cstdio> char st[100]; int main() { scanf("%s", st); for (int i = 0; st[i]; ++i) { if ('A' <= st[i] && st[i]<= 'Z') st[i] += 1; } printf("%s\n", st); return 0; }
讀題意就是將所有大寫字母變成字母后一位,如'A'變成'B','E'變成'F'.
輸出:RuanHuoMianTai
2
#include <cstdio> int main() int x; scanf("%d",&x); int res = 0; for (int i=0;i<x;++i) { if (i*i%x == 1) { ++res; } } printf("%d", res); return 0; }
讀題意得 0-15 每一個數的平方模15 是不是等於1
枚舉和模的時候要細心
輸出:4
3
#include <iostream> using namespace std; int n,m; int findans(int n,int m){ if (n==0) return m; if (m==0) return n % 3; return findans(n-1,m)-findans(n,m-1)+findans(n-1,m-1); } int main(){ cin>>n>>m; cout<<findans(n,m)<<endl; return 0; }
做的時候暴力模擬,后來知道可以用表格。
$f[i][j]=f[i-1][j]-f[i][j-1]+f[i-1][j-1]$
表格長這樣
n/mn/m | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
1 | 1 | 0 | 3 | 2 | 5 | 4 | 7 |
2 | 2 | -1 | 4 | 1 | 6 | 3 | 8 |
3 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
4 | 1 | 0 | 3 | 2 | 5 | 4 | 7 |
5 | 2 | -1 | 4 | 1 | 6 | 3 | 8 |
輸出:8
4
#include <cstdio> int n,d[100]; bool v[100]; int main(){ scanf("%d",&n); for (int i=0;i<n;++i) { scanf("%d",d+i); v[i]=false; } int cnt=0; for (int i=0;i<n;++i) { if (!v[i]){ for (int j=i;!v[j];j=d[j]) { v[j]=true; } ++cnt; } } printf("%d\n", cnt); return 0; }
暴力模擬即可
輸出:6
完善程序
1.最大公約數之和
(1)
$i*i$,枚舉到$\sqrt{n}$
(2)
$n/i$
(3)
return a
(4)
a%b
(5)
gcd(a[i],a[j])+ans
2.雙向鏈表求排列
(1)
a[x]=i
(2)
i+1
(3)
R[a[i]],對稱填
(4)
a[i],剛開始對稱填錯了,雙向鏈表操作
(5)
R[i]