牛客周賽 Round 67 A~F題解
- 牛客周賽 Round 67 A~F題解
- Preface
- 所有程式碼前面的火車頭
- Problem A.排序危機
- Problem B.小歪商店故事:卷
- Problem C.小苯的計算式
- Problem D.K
- Problem E.小苯的區間選數
- Problem F.小Z的樹遷移
- PostScript
- Preface
Preface
好久沒v過牛客周賽了,但估計這場強度不高是特例吧,感覺AK還是不太難的,最後一題也還好,想到了做起來也不太難,還是多v挑戰賽吧。
所有程式碼前面的火車頭
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <set>
#include <queue>
#include <map>
#include <unordered_map>
#include <iomanip>
#define endl '\n'
#define int long long
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define rep2(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
template<typename T>
void cc(vector<T> tem) { for (auto x : tem) cout << x << ' '; cout << endl; }
void cc(int a) { cout << a << endl; }
void cc(int a, int b) { cout << a << ' ' << b << endl; }
void cc(int a, int b, int c) { cout << a << ' ' << b << ' ' << c << endl; }
void fileRead() {
#ifdef LOCALL
freopen("D:\\AADVISE\\cppvscode\\CODE\\in.txt", "r", stdin);
freopen("D:\\AADVISE\\cppvscode\\CODE\\out.txt", "w", stdout);
#endif
}
void kuaidu() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); }
inline int max(int a, int b) { if (a < b) return b; return a; }
inline int min(int a, int b) { if (a < b) return a; return b; }
void cmax(int& a, const int b) { if (b > a) a = b; }
void cmin(int& a, const int b) { if (b < a) a = b; }
using PII = pair<int, int>;
using i128 = __int128;
Problem A.排序危機
只能說這個簽到給我寫複雜了,其實只需要先輸出小寫字母,再輸出數字,最後輸出大寫字母就好了,我卻唐成了結構體排序,複雜度還多了一個\(log\)
//--------------------------------------------------------------------------------
const int N = 1e5 + 10;
const int M = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 1e16;
int n, m, T;
//--------------------------------------------------------------------------------
//struct or namespace:
struct node {
char x;
int val;
int id;
};
node A[N];
//--------------------------------------------------------------------------------
signed main() {
fileRead();
kuaidu();
T = 1;
//cin >> T;
while (T--) {
cin >> n;
rep(i, 1, n) {
char a; int b; cin >> a;
if (a <= '9' and a >= '0') b = 2;
if (a <= 'z' and a >= 'a') b = 1;
if (a <= 'Z' and a >= 'A') b = 3;
A[i] = { a,b,i };
}
sort(A + 1, A + n + 1, [&](const node& q1, const node& q2) {
if (q1.val == q2.val) return q1.id < q2.id;
return q1.val < q2.val;
});
rep(i, 1, n) {
cout << A[i].x;
}
}
return 0;
}
/*
*/
Problem B.小歪商店故事:卷
按照題意模擬就好了,直接計算\(b*c/d\)就好了,要注意整除的情況。
//--------------------------------------------------------------------------------
const int N = 1e5 + 10;
const int M = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 1e16;
int n, m, T;
//--------------------------------------------------------------------------------
//struct or namespace:
//--------------------------------------------------------------------------------
signed main() {
fileRead();
kuaidu();
T = 1;
cin >> T;
while (T--) {
int a, b, c, d;
cin >> a >> b >> c >> d;
int aa = b * c / d;
if ((b * c) % d == 0) aa -= 1;
cout << a - aa << ' ';
}
return 0;
}
/*
*/
Problem C.小苯的計算式
\(C\)的範圍比較小,一眼直接暴力列舉\(A\)即可,\(B\)也就能直接\(C-A\)出來了。
//--------------------------------------------------------------------------------
const int N = 1e5 + 10;
const int M = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 1e16;
int n, m, T;
//--------------------------------------------------------------------------------
//struct or namespace:
//--------------------------------------------------------------------------------
signed main() {
fileRead();
kuaidu();
T = 1;
// cin >> T;
while (T--) {
int c; cin >> n >> c;
n -= to_string(c).size() + 2;
int ans = 0;
rep(i, 0, c) {
string a = to_string(i), b = to_string(c - i);
if (a.size() + b.size() == n) ans++;
}
cc(ans);
}
return 0;
}
/*
*/
Problem D.K
感覺總算有點不是給小白做的題了,區域賽簽到題水平?
當\(k==n\)的時候直接一直輸出\(1\)就好了。
隨便手玩一下,會發現可以直接構造1,2,1,2,這種長度是\(n\)的序列我們可以造出來\(k=n-1\)的情況來,如果\(k<n-1\)的情況,我們就可以直接讓後面一直迴圈一個數字,變成1,2,1,2,2, 2, 2,這種就能夠滿足了,程式碼中間只需要注意是讓\(1\)迴圈還是\(2\)迴圈就好。
順便要注意會有\(k>n\)的情況,要特判\(NO\),因為這個\(WA\)了一發。TAT
//--------------------------------------------------------------------------------
const int N = 1e5 + 10;
const int M = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 1e16;
int n, m, T;
//--------------------------------------------------------------------------------
//struct or namespace:
//--------------------------------------------------------------------------------
signed main() {
fileRead();
kuaidu();
T = 1;
//cin >> T;
while (T--) {
int k; cin >> n >> k;
if (k > n) {
cout << "NO" << endl;
continue;
}
cout << "YES" << endl;
if (n == k) {
rep(i, 1, n) cout << 1 << " ";
continue;
}
if (n - 1 == k) {
for (int i = 1; i <= n; i += 2) {
cout << "1 2 ";
}
continue;
}
if (k % 2 == 0) {
for (int i = 1; i <= k / 2; i++) {
cout << "1 2 ";
}
cout << 1 << " ";
for (int i = 1; i <= n - k - 1; i++) {
cout << 1 << " ";
}
}
else {
for (int i = 1; i <= (k + 1) / 2; i++) {
cout << "1 2 ";
}
for (int i = 1; i <= n - k - 1; i++) {
cout << 2 << " ";
}
}
}
return 0;
}
/*
*/
Problem E.小苯的區間選數
首先應該一眼反應過來\(sum\)就是要在\(l=l_1+l_2\)到\(r=r_1+r_2\)之間選擇就好了,竟然一開始沒看出來。。。
之後還是手玩一下會發現,比如\(123,159。\)我們只需要找到兩個數字第一個不相等的地方,使這一個位置是\(r-1\),後面一直變成\(99999\)就好了。如果\(l\)和\(r\)的長度不一樣,給\(l\)補上前導\(0\)就好了。
但要注意如果r本身就是\(999\)結尾的情況,我們只需要再計算一下\(sum=\)\(l\)和\(r\)的情況就可以解決。
//--------------------------------------------------------------------------------
const int N = 1e5 + 10;
const int M = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 1e16;
int n, m, T;
//--------------------------------------------------------------------------------
//struct or namespace:
//--------------------------------------------------------------------------------
signed main() {
fileRead();
kuaidu();
T = 1;
cin >> T;
while (T--) {
int l1, l2, r1, r2;
cin >> l1 >> r1 >> l2 >> r2;
int l = l1 + l2, r = r1 + r2;
int ans1 = 0, ans2 = 0, ans3 = 0;
string s1 = to_string(l), s2 = to_string(r);
for (auto& x : s1) {
ans1 += x - '0';
}
for (auto& x : s2) {
ans2 += x - '0';
}
while (s1.size() != s2.size()) s1 = '0' + s1;
int len = s1.size();
int num = 0;
for (int i = 0; i < len; i++) {
if (s1[i] == s2[i]) {
ans3 += s1[i] - '0';
num = (s1[i] - '0') + num * 10;
continue;
}
ans3 += (s2[i] - '0' - 1);
ans3 += 9 * (len - 1 - i + 1 - 1);
break;
}
ans1 = max({ ans1,ans2,ans3 });
cc(ans1);
}
return 0;
}
/*
*/
Problem F.小Z的樹遷移
只能說寫這題腦子有些唐了,竟然預設成這個樹會是一個均攤的樹,算下來發現\(logn\)不到20,直接寫了個暴力\(dp\),只能說腦子太秀逗了。
之後冷靜思考,發現純純暴力啟發式合併就好了。先離線處理詢問。給每一個點開一個並查集,裡面開一個\(map\),\(key\)是層數,\(val\)是存有這個點子樹內每一層的\(pre[i]\)最大值就好了,\(pre[i]\)代表\(i\)點到達根節點之間的距離。計算向下走\(d\)次的答案時便是\(mp[dep[x]+d]-pre[x]\)。
關於啟發式合併的複雜度這裡便不再贅述,用的是比較好寫的寫法,複雜度會因為\(map\)多一個\(log\),可以使用樹上啟發式合併,複雜度是會少一個\(log\)的。
時間複雜度是\(O(n*logn*logn)\)
//--------------------------------------------------------------------------------
const int N = 1e5 + 10;
const int M = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 1e16;
int n, m, T;
vector<PII> A[N];
vector<PII> qs[N];
int pre[N], dep[N];
int ans[N];
//--------------------------------------------------------------------------------
//struct or namespace:
namespace DSU {
const int N = 1e5 + 10;
struct Info {
int fa;
int siz;
map<int, int> mp;
};
Info dsu[N];
void init(int n) {
//TO DO 記得初始化
rep(i, 0, n) {
dsu[i].fa = i, dsu[i].siz = 1;
}
}
int find(int x) { if (x == dsu[x].fa) return x; return dsu[x].fa = find(dsu[x].fa); }
void merge(int x, int y) {
x = find(x), y = find(y);
if (x == y) return;
dsu[y].fa = dsu[x].fa;
if (dsu[x].siz < dsu[y].siz) swap(x, y);
dsu[y].fa = dsu[x].fa;
dsu[x].siz += dsu[y].siz;
for (auto [a, b] : dsu[y].mp) {
cmax(dsu[x].mp[a], b);
}
}
bool same(int x, int y) {
x = find(x), y = find(y);
if (x == y) return 1; return 0;
}
int size(int x) { return dsu[find(x)].siz; }
}
using DSU::dsu;
//--------------------------------------------------------------------------------
void dfs(int x, int pa) {
dep[x] = dep[pa] + 1;
for (auto [y, val] : A[x]) {
if (y == pa) continue;
pre[y] = pre[x] + val;
dfs(y, x);
}
dsu[x].mp[dep[x]] = pre[x];
for (auto [y, val] : A[x]) {
if (y == pa) continue;
DSU::merge(x, y);
}
int rt = DSU::find(x);
for (auto [dis, id] : qs[x]) {
if (dsu[rt].mp.find(dis + dep[x]) == dsu[rt].mp.end()) ans[id] = -1;
else ans[id] = dsu[rt].mp[dis + dep[x]] - pre[x];
}
}
signed main() {
fileRead();
kuaidu();
T = 1;
//cin >> T;
while (T--) {
cin >> n;
rep(i, 1, n - 1) {
int a, b, c; cin >> a >> b >> c;
A[a].push_back({ b,c });
A[b].push_back({ a,c });
}
int q; cin >> q;
rep(i, 1, q) {
int x, dep; cin >> x >> dep;
qs[x].push_back({ dep,i });
}
DSU::init(n);
pre[1] = 0;
dfs(1, 0);
rep(i, 1, q) {
cout << ans[i] << endl;
}
}
return 0;
}
/*
*/
PostScript
最近太擺了,感覺EC-Final肯定鐵了,也不太有訓練的心態了。慢慢康復訓練吧。