題目A - 咕咕東的奇遇
題意
咕咕東是個貪玩的孩子,有一天,他從上古遺蹟中得到了一個神奇的圓環。這個圓環由字母表組成首尾相接的環,環上有一個指針,最初指向字母a。咕咕東每次可以順時針或者逆時針旋轉一格。例如,a順時針旋轉到z,逆時針旋轉到b。咕咕東手裏有一個字符串,但是他太笨了,所以他來請求你的幫助,問最少需要轉多少次。
Input
zeus
Output
18
思路
考慮上衣字符撥到當前字符逆時針還是順時針即可。
具體的判斷可以用,注意取模:
- 順時針: 當前字符 上一字符
- 逆時針:26 (當前字符 上一字符)
總結
憨憨的我上來直接24個英文字母。簽到題
代碼
#include <iostream>
#include <cstdio>
using namespace std;
int main() {
string s;
cin >> s;
int ans = 0;
int k = 0;
for (int i = 0; i < s.size(); i++) {
int cur = (26 + s[i] - 'a' - k) % 26;
// ans += min((s[i] - 'a' - k) % 26, 26 - ((s[i] - 'a' - k) % 26));
ans += min(cur, 26 - cur);
k = s[i] - 'a';
// cout << k << " " << ans << endl;
}
cout << ans;
return 0;
}
題目B - 咕咕東想喫飯
題意
咕咕東考試周開始了,考試周一共有天。他不想考試周這麼累,於是打算每天都喫頓好的。他決定每天都喫生煎,咕咕東每天需要買個生煎。但是生煎店爲了刺激消費,只有兩種購買方式:①在某一天一次性買兩個生煎。②今天買一個生煎,同時爲明天買一個生煎,店家會給一個券,第二天用券來拿。沒有其餘的購買方式,這兩種購買方式可以用無數次,但是咕咕東是個節儉的好孩子,他訓練結束就走了,不允許訓練結束時手裏有券。咕咕東非常有錢,你不需要擔心咕咕東沒錢,但是咕咕東太笨了,他想問你他能否在考試周每天都能恰好買個生煎。
其中
,
Input
4
1 2 1 2
Output
2
思路
考慮對於第天,假設買了m個煎餅,其第二種方案對第天的影響可以轉變爲至多一次。
因爲,假設第天選了2次方案二,其等價於第天選1次方案一,第天選1次方案一。
故問題可以轉化爲先考慮最後一天,若爲偶數個,直接全選擇方案1,若爲奇數個,選擇一次方案1。並讓前一天總煎餅數-1(選擇一次方案2)。
則問題轉化爲,對於當前天:
- 若煎餅數爲偶數,則繼續。
- 若煎餅數爲基數,則令前一天煎餅數-1。
輸出NO
的情況爲當前天煎餅數 ,或第一天煎餅數爲基數個。否則輸出YES
。
總結
這題還是挺有意思的,不過數據有點水(逃) 。全輸出YES
能拿到不少分吧。
代碼
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
using namespace std;
int v[100010];
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> v[i];
}
int flag = 0;
for (int i = n; i; i--) {
if (flag == 1) {
v[i] -= 1;
if (v[i] < 0) {
cout << "NO";
return 0;
}
}
if (v[i] % 2 == 0) {
flag = 0;
} else {
flag = 1;
}
}
if (flag == 1) {
cout << "NO";
} else {
cout << "YES";
}
return 0;
}
題目C - 可怕的宇宙射線
題意
衆所周知,瑞神已經達到了CS本科生的天花板,但殊不知天外有天,人外有苟。在浩瀚的宇宙中,存在着-種叫做苟狗的生物, 這種生物天生就能達到人類研究生的知識水平,並且天生擅長CSP,甚至有全國第一的水平!但最可怕的是,它可以發出宇宙射線!宇宙射線可以摧毀人的智商,進行降智打擊!
宇宙射線會在無限的二維平面上傳播(可以看做一個二維網格圖),初始方向默認向上。宇宙射線會在發射出一段距離後分裂,向該方向的左右方向分裂出兩條宇宙射線,同時威力不變!宇宙射線會分裂次,每次分裂後會在分裂方向前進個單位長度。
現在瑞神要帶着他的小弟們挑戰苟狗,但是瑞神不想讓自己的智商降到普通本科生zjm那麼菜的水平,所以瑞神來請求你幫他計算出共有多少個位置會被"降智打擊”。
Input
4
4 2 3 2
Output
39
思路
樸素的DFS,和BFS能拿到40分。據說剪枝後可以A掉,但是要注意考慮層數,(第4次和21次以同一方向道道某個點並不能剪掉),否則會WA。下面給出一種好的解法(這裏感謝下hf大佬。
首先考慮分裂30次,顯然會TLE
。考慮每次分裂是對稱的,其實我們只需要考慮一半就行,如只考慮向右邊分裂,把分裂後的圖沿着對稱軸對稱過去,這樣問題變成了30次圖的對稱複製。
至於怎麼對稱,考慮:
我們已知線段L,點A,求點A的對稱點B。
那麼問題就很簡單了,高數學過(我卻忘了,LY老師Dbq):
- 對於上、下、左、右。很簡單
- 對於其它方向,用下式推導,結果很好看。
總結
set用法
這題我算錯複雜度了,以爲樸素的dfs就能A。(問問自己,第幾次這樣了???)。然後玩了半小時(RNG NB)。最後看出來怎麼做了,奈何不會算對稱點,最後拿了暴力的40分,只能補題了。
代碼
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
struct re {
int x, y;
bool operator<(const re& a) const { return x != a.x ? x < a.x : y < a.y; }
};
set<re> M;
int ans;
int fx[] = {0, 1, 1, 1, 0, -1, -1, -1};
int fy[] = {1, 1, 0, -1, -1, -1, 0, 1};
int v[50], n;
void dfs(re cur, int k, int flag) {
if (k > n) return;
// cout << k << " " << flag << endl;
dfs({cur.x + fx[flag] * v[k], cur.y + fy[flag] * v[k]}, k + 1, (flag + 1) % 8);
set<re> temp;
for (auto& i : M) {
if (flag == 0 || flag == 4)
temp.insert({cur.x * 2 - i.x, i.y});
else if (flag == 1 || flag == 5)
temp.insert({i.y + cur.x - cur.y, i.x - cur.x + cur.y});
else if (flag == 2 || flag == 6)
temp.insert({i.x, cur.y * 2 - i.y});
else if (flag == 3 || flag == 7)
temp.insert({cur.x + cur.y - i.y, cur.x + cur.y - i.x});
}
M.insert(temp.begin(), temp.end());
for (int i = 1; i <= v[k]; i++) {
M.insert({cur.x + fx[flag] * i, cur.y + fy[flag] * i});
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> v[i];
}
dfs({0, 0}, 1, 0);
cout << M.size();
return 0;
}