---
tags: 成大高階競技程式設計 2020
---
# 2020高階競程課前賽-題解
## [pA Calculating EAN check digit](https://judge.csie.ncku.edu.tw/problems/4)
- Task Provider:tsai_mh
- Task Setter:leo900807
### 首殺 TedLiao (00:04)
### 解法說明
本題為模擬題,僅需依照題目所述:
1. 將第 $2,4,6,8,10,12$ 位數的數字相加為 $a$
2. 將第 $1,3,5,7,9,11$ 位數的數字相加為 $b$
3. 將 $a$ 乘 $3$ 並加上 $b$ 為 $x$ , $x=3a+b$
4. 將 $x$ 減 $1$ 為 $y$ , $y=x-1$
5. 將 $y$ 對 $10$ 取餘數為 $z$ , $z=y\ \%\ 10$
6. $9-z$ 即為答案
算式: $\text{Ans}=(9-(b+3a-1)\ \%\ 10)$
### 標準程式
:::spoiler
```cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
int odd = 0, even = 0;
string str;
cin >> str;
for ( int i = 0 ; i < 12 ; ++i )
if ( i % 2 == 1 )
even += str[i] - '0';
else
odd += str[i] - '0';
cout << 9 - ( odd + 3 * even - 1 ) % 10 << '\n';
}
```
:::
## [pB Beaufort scale](https://judge.csie.ncku.edu.tw/problems/5)
- Task Provider:tsai_mh
- Task Setter:leo900807
### 首殺 Mandy (00:04)
### 解法說明
只要照著題目所述判斷條件就好。
### 標準程式
:::spoiler
```cpp
#include <stdio.h>
int main()
{
int wind_speed;
scanf("%d", &wind_speed);
if(wind_speed < 1)
printf("Calm\n");
else if(wind_speed < 4)
printf("Light air\n");
else if(wind_speed < 28)
printf("Breeze\n");
else if(wind_speed < 48)
printf("Gale\n");
else if(wind_speed <= 63)
printf("Storm\n");
else
printf("Hurricane\n");
return 0;
}
```
:::
## [pC 藍的競程之旅--魔法藥](https://judge.csie.ncku.edu.tw/problems/7)
- Task Provider:ian
- Task Setter:ian
### 首殺 TedLiao (00:11)
### 解法說明
本題的魔法藥優先度跟魔法藥的種類相同,假設某個魔法藥的優先度是 $j$ 其實就代表他是第 $n-j+1$ 個加入的藥,依照此方法寫出以下程式。
### 標準程式
:::spoiler
```cpp
#include <iostream>
using namespace std;
int a[500050];
int n;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
int i, j;
for (i = 1; i <= n; i++) {
cin >> j;
a[n - j + 1] = i;
}
for (i = 1; i <= n; i++) {
cout << a[i] << " ";
}
cout << endl;
}
```
:::
## [pD 彩彩劈瓦](https://judge.csie.ncku.edu.tw/problems/8)
- Task Provider:ys
- Task Setter:ys
### 首殺 -- (-:-)
### 解法說明
對於目前修瓦值為 $P$,考慮劈與不劈都能影響到最終答案﹔最多共能劈多少瓦
所以令狀態為 $dp(i, P)$ 表示考慮目前有修瓦值 $P$ 且已評估過第 $1$ 到 $i$ 天的瓦
第 $i$ 天結束了,彩彩能考慮劈不劈 $i+1$ 天的瓦
- 劈
則 $dp(i+1, P - \min(P, a_{i+1})) = dp(i, P) + \min(P, a_{i+1})$
由於 $P$ 有可能不夠劈全部的瓦 $a_{i+1}$,所以取最小值 $\min(P, a_{i+1})$
- 不劈
則 $dp(i+1, \min(P+a_{i+1}, L)) = dp(i, P)$
修瓦值的上限為 $L$,則 $P$ 只能加至 $L$,於是取最小值 $\min(P+a_{i+1}, L)$
而第 $1$ 天開始前 $P = 0$,彩彩只能選擇不劈 $dp(1, \min(a_1, L)) = 0$
且求解狀態前將所有狀態值設為**無限小**,表示尚未得解
依照原先狀態定義,最終答案為 $\max\{dp(n, P)\ |\ 0\leq P\leq L\}$
### 標準程式
:::spoiler
#### version 1:
```cpp
#include<cstdio>
#include<algorithm>
using namespace std;
int const maxn = 3e3 + 10, maxl = 3e3 + 10;
int const INF = 0x3f3f3f3f;
int n, L, a[maxn], dp[maxn][maxl];
int main()
{
scanf("%d%d", &n, &L);
for(int i = 0; i < n; i++) scanf("%d", &a[i]);
for(int i = 0; i < n; i++)
for(int P = 0; P <= L; P++) dp[i][P] = -INF;
dp[0][min(L, a[0])] = 0;
for(int i = 1; i < n; i++)
for(int P = L; P >= 0; P--) {
int g = min(P, a[i]);
if(P-g >= 0) dp[i][P-g] = max(dp[i][P-g], dp[i-1][P] + g);
if(P+a[i] <= L) dp[i][P+a[i]] = max(dp[i][P+a[i]], dp[i-1][P]);
else dp[i][L] = max(dp[i][L], dp[i-1][P]);
}
int ans = 0;
for(int P = 0; P <= L; P++) ans = max(ans, dp[n-1][P]);
printf("%d\n", ans);
return 0;
}
```
#### version 2:
```cpp
#include <bits/stdc++.h>
using namespace std;
using ll = long long int;
ll dp[3333][3333], a[3333], n, m;
ll calc(int now, ll p) {
if (now >= n || dp[now][p]) return dp[now][p];
ll dif = p - a[now];
if (dif > 0) {
return dp[now][p] = max(calc(now + 1, min(m, p + a[now])), a[now] + calc(now + 1, dif));
} else {
return dp[now][p] = max(calc(now + 1, min(m, p + a[now])), p + calc(now + 1, 0));
}
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; i++) cin >> a[i];
cout << calc(0, 0) << endl;
}
```
:::
## [pE Seeeeeeeeeeeeeg](https://judge.csie.ncku.edu.tw/problems/9)
- Task Provider:Miohitokiri5474
- Task Setter:Miohitokiri5474
### 首殺 -- (-:-)
### 解法說明
很簡單的RMQ。
剛開始看到題目可能會想要幹這種事
```cpp
// by. MiohitoKiri5474
#include<bits/stdc++.h>
using namespace std;
int data[maxN];
int main(){
int n, m, l, r, ma, type, cnt = 0;
cin >> n >> m;
for ( int i = 1 ; i <= n ; i++ )
cin >> data[i];
while ( m-- ){
cin >> type;
if ( type == 1 )
cin >> l >> data[l];
else{
ma = -1;
cin >> l >> r;
for ( int i = l ; i <= r ; i++ )
ma = max ( ma, data[i] );
cout << ma << '\n';
}
}
}
```
於是你就會得到一個TLE。
原因很簡單,暴力解的複雜度最差為 $O (nm)$,通常在時限1000ms的情況下不會過。
官方題解為區間RMQ問題,可以用一個很基礎的資料結構解決——線段樹。(因為以後的課程會講到,所就不在這邊寫落落長的教學,如果有興趣的可以先上網尋找相關資料)
### 標準程式
:::spoiler
```cpp
// by. MiohitoKiri5474
#include<bits/stdc++.h>
using namespace std;
#define maxN 100005
int seg[maxN << 2];
void update ( int l, int r, int index, int value, int n ){
if ( l == r )
seg[n] = value;
else{
int mid = ( l + r ) >> 1, leftSon = n << 1, rightSon = leftSon | 1;
if ( index <= mid )
update ( l, mid, index, value, leftSon );
else
update ( mid + 1, r, index, value, rightSon );
seg[n] = max ( seg[leftSon], seg[rightSon] );
}
}
int query ( int l, int r, int nowL, int nowR, int n ){
if ( l <= nowL && nowR <= r )
return seg[n];
int mid = ( nowL + nowR ) >> 1, leftSon = n << 1, rightSon = leftSon | 1;
if ( r <= mid )
return query ( l, r, nowL, mid, leftSon );
if ( mid < l )
return query ( l, r, mid + 1, nowR, rightSon );
return max ( query ( l, r, nowL, mid, leftSon ), query ( l, r, mid + 1, nowR, rightSon ) );
}
int main(){
ios::sync_with_stdio ( false );
cin.tie ( 0 );
cout.tie ( 0 );
int n, m, l, r, value, type;
cin >> n >> m;
for ( int i = 1 ; i <= n ; i++ ){
cin >> value;
update ( 1, n, i, value, 1 );
}
while ( m-- ){
cin >> type >> l >> r;
if ( type == 1 )
update ( 1, n, l, r, 1 );
else
cout << query ( l, r, 1, n, 1 ) << '\n';
}
}
```
:::
## [pF 探望麻衣](https://judge.csie.ncku.edu.tw/problems/10)
- Task Provider:Miohitokiri5474
- Task Setter:Miohitokiri5474
### 首殺 misclicked (01:29)
### 解法說明
單源最短路裸題
標程為 SPFA,不過因為用了怪怪的優化方法,所以下面放的 code 是 Dijkstra
想要 SPFA 做法的可以來問(?
### 標準程式
:::spoiler
```cpp
#include<bits/stdc++.h>
using namespace std;
#define maxN 100005
vector < pair < int, long long > > edges[maxN];
long long dis[maxN];
int main(){
ios::sync_with_stdio ( false );
cin.tie ( 0 );
cout.tie ( 0 );
int n, m, u, v, w, now;
long long d;
cin >> n >> m;
while ( m-- ){
cin >> u >> v >> w;
edges[u].emplace_back ( v, w );
edges[v].emplace_back ( u, w );
}
priority_queue < pair < long long, int >, vector < pair < long long, int > >, greater < pair < long long, int > > > pq;
memset ( dis, 0x3f3f3f3f3f3f3f, sizeof ( dis ) );
dis[0] = 0;
pq.push ( make_pair ( 0, 0 ) );
while ( !pq.empty() ){
now = pq.top().second, d = pq.top().first;
pq.pop();
if ( dis[now] < d )
continue;
for ( auto i: edges[now] ){
if ( dis[i.first] > d + i.second ){
dis[i.first] = d + i.second;
pq.push ( make_pair ( dis[i.first], i.first ) );
}
}
}
for ( int i = 0 ; i < n ; i++ )
cout << dis[i] << ' ';
cout << '\n';
}
```
:::
## [pG 貪心的小明](https://judge.csie.ncku.edu.tw/problems/11)
- Task Provider:raiso
- Task Setter:raiso
### 首殺 Gary (00:17)
### 解法說明
不要偷懶,考慮所有可能性(6種),然後你就知道了,但是因為位數很高,使用 int 會 overflow ,所以...
以下提供的範例很長,當然可以寫個更簡潔,但是這裡先使用最暴力的方法,因為暴力是入門的第一課 - **寫出你的想法**。
### 標準程式
:::spoiler
#### C++ code
```cpp
#include <bits/stdc++.h>
using namespace std;
long long tennn(long long a) {
int c = 0;
while(a >= 10) a /= 10, c++;
long long b = 1;
for(int i = 0; i < c+1; i++) b *= 10;
return b;
}
int main() {
long long B[3];
long long A[6] = {};
for(int i = 0; i < 3; i++) cin >> B[i];
int c = 0;
for(int i = 0; i < 3; i++) for(int j = 0; j < 3; j++) for(int k = 0; k < 3; k++) if(i != j && i != k && j != k) {
A[c++] = B[i] + B[j]*tennn(B[i]) + B[k] * tennn(B[i]) * tennn(B[j]);
}
long long maxi = 0;
for(int i = 0; i < c; i++) maxi = maxi > A[i]? maxi: A[i];
cout << maxi << endl;
return 0;
}
```
#### Python code
```python
a, b, c = input().strip().split(' ')
s = [a+b+c,a+c+b,b+a+c,b+c+a,c+a+b,c+b+a]
s = map(int, s)
print(max(s))
```
:::