Lời Giải Khảo Sát Đội Tin HQV Đợt 2 2024
Bài 1. EVEN

Lời giải
Ta sẽ đếm số số lẻ từ , và số số chẵn từ .
Rồi áp dụng công thức sau:
Tổng số lẻ đầu tiên từ :
Tổng số chẵn đầu tiên từ :
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define nl '\n'
ll solve(ll n)
{
ll even, odd;
if (n % 2 == 0)
{
even = odd = n / 2;
}
else
{
even = n / 2;
odd = even + 1;
}
return max(odd * odd, even * (even + 1));
}
int main()
{
int t;
cin >> t;
while (t--)
{
ll n;
cin >> n;
cout << solve(n) << nl;
}
return 0;
}Bài 2. SUM


Lời giải
Giả sử ban đầu mọi phần tử trong mảng nhân với :

Nếu chọn vị trí bất kỳ và nhân các phần tử từ vị trí với thì ta được:

hoặc

Tương tự với bất kỳ từ :

hoặc

Nhưng nếu ta thực hiện cả 2 thao tác thì luôn có một đoạn con ở giữa sẽ vẫn nhân với như ban đầu:
Trường hợp :

Trường hợp :

Trường hợp :

Từ các quan sát như vậy ta kết luận được các trường hợp chính như sau:
- Toàn bộ là .
- Toàn bộ là .
- Một đoạn ở giữa 2 đoạn .
- Mảng chia thành 2 phần .
Vậy từ đây ta có được ý tưởng như sau, kết quả của bài toán chính là giá trị lớn nhất của:
- Tổng của toàn bộ mảng nhân với .
- Tổng của toàn bộ mảng nhân với .
- lần tổng lớn nhất của 1 đoạn con liên tiếp trong dãy ban đầu + tổng toàn bộ mảng nhân với .
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define nl '\n'
int main()
{
int n, a;
cin >> n;
int total = 0, current = 0, maxSum = 0;
for (int i = 0; i < n; i++)
{
cin >> a;
total += a;
current = max(a, current + a);
maxSum = max(maxSum, current);
}
cout << 2 * maxSum - total;
return 0;
}Bài 3. STRING

Lời giải
Vì chỉ có ký tự chữ cái Latinh, nên mức độ của chuỗi có giá trị nằm trong khoảng .
Ý tưởng như sau:
Ta sẽ tính mức độ của tất cả các chuỗi con kết thúc tại vị trí . Và sau đó tổng hợp lại các kết quả ấy.
Ví dụ có chuỗi .
Giả sử ta cần đếm mức độ của tất cả các chuỗi con kết thúc tại vị trí cuối cùng :

Ta thấy rằng số chuỗi con có mức độ:
- khi .
- khi .
- khi .
- khi .
Với là vị trí xuất hiện cuối cùng của , là vị trí xuất hiện cuối cùng của , là vị trí xuất hiện cuối cùng của , là toàn bộ chuỗi con kết thúc tại đều có mức độ là .
Từ đây ta có ý tưởng, với mỗi ký tự có trong chuỗi khi xét đến , ta sẽ lưu lại vị trí xuất hiện cuối cùng của các ký tự đó vào mảng .

Và sau đó thêm 1 phần tử , sắp xếp mảng để tạo ra mảng như sau:

Vậy ở ví dụ này, số chuỗi con có mức độ sẽ là:
Trong trường hợp tổng quát hơn ta có chữ cái Latinh phân biệt, lúc đó mảng sẽ có phần tử :
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define nl '\n'
int main()
{
string s;
cin >> s;
vector<int> p(26, -1);
vector<ll> ans(26, 0);
for (int i = 0; i < s.size(); i++)
{
p[s[i] - 'a'] = i;
vector<int> x = p;
x.push_back(-1);
sort(x.begin(), x.end());
for (int j = 1; j <= 26; j++)
ans[26 - j] += x[j] - x[j - 1];
}
cout << find(ans.begin(), ans.end(), 0) - ans.begin() << nl;
for (int i = 0; i < ans.size() && ans[i] != 0; i++)
cout << ans[i] << nl;
return 0;
}Bài 4. DISTANCE

Lời giải
Như đề bài đã cho, đầu vào là 1 cây, nên đây là một đồ thị liên thông, không có chu trình với đỉnh.
Vì thế đường đi giữa 2 node bất kỳ là duy nhất.
Ta có thể suy ngay được ra là đường đi xa nhất giữa 2 node trong cây sẽ có 2 đầu là 2 node lá. Bởi nếu 1 trong 2 node đấy không phải lá thì có đường đi đó vẫn có thể tiếp tục đi đến node con và tạo ra đường đi xa hơn.
Ta có ý tưởng như sau:
- DFS từ node gốc cây, để tìm ra node lá xa nhất và lưu lại nốt lá đó gọi là .
- Rồi lại DFS từ node lá (giờ ta coi như là một node gốc) để tìm ra node lá xa nhất gọi là .
Vậy khoảng cách xa nhất giữa 2 đỉnh bất kỳ trên cây chính là khoảng cách giữa và .
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define nl '\n'
const int mx = 2e5 + 2;
vector<vector<int>> adj(mx, vector<int>());
vector<bool> visit(mx);
int fv = -1, md = -1;
void dfs(int u, int d)
{
visit[u] = true;
if (d > md)
{
md = d;
fv = u;
}
for (auto v : adj[u])
{
if (!visit[v])
dfs(v, d + 1);
}
}
int main()
{
int n;
cin >> n;
int root = 0;
for (int i = 1; i <= n; i++)
{
int p;
cin >> p;
adj[i].push_back(p);
adj[p].push_back(i);
if (!p)
root = i;
}
visit.assign(mx, false);
dfs(root, 0);
visit.assign(mx, false);
md = -1;
dfs(fv, 0);
cout << md;
return 0;
}