Lời Giải HSG Tin TP Hà Nội - 2023

November 4, 2025 August 17, 2024
Author Author Hung Nguyen Tuong

Bài 1. Số chính phương đặc biệt

Số chính phương đặc biệt là số chính phương được tạo bởi một số nguyên tố.

Ví dụ: 4=2×2;9=3×3;36=6×64 = 2 \times 2; 9 = 3 \times 3; 36 = 6 \times 6 nên 4499 là số chính phương đặc biệt còn 3636 thì không phải là số chính phương đặc biệt.

Yêu cầu

Cho 2 số nguyên dương a,ba, b. Hãy đếm xem trong đoạn [a,b][a,b] có bao nhiêu số chính phương đặc biệt?

Dữ liệu

Vào từ tệp văn bản CP.INP: gồm hai số nguyên dương a,ba, b (2ab1012)(2 \leq a \leq b \leq 10^{12}).

Kết quả

Ghi ra tệp văn bản CP.OUT: gồm một dòng chứa một số duy nhất là kết quả của bài toán.

Ràng buộc

  • Có 80% số test ứng với 80% số điểm của bài thoả mãn 2ab1062 \leq a \leq b \leq 10^6.
  • 20% số test còn lại ứng với 20% số điểm của bài không có ràng buộc gì thêm.

Ví dụ

CP.INPCP.OUT
2 102

Lời giải

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
    ll a, b;
    cin >> a >> b;
    int n = 1e6;
    vector<bool> sieve(n + 1, true);
    for (int i = 2; i <= sqrt(n); i++)
    {
        if (sieve[i])
        {
            for (int j = i * i; j <= n; j += i)
                sieve[j] = false;
        }
    }
    ll ans = 0;
    for (ll i = sqrt(a); i * i <= b; i++)
    {
        ll ii = i * i;
        if (sieve[i] && a <= ii && ii <= b)
            ans++;
    }
    cout << ans;
    return 0;
}

Bài 2. Bảng số

Cho một bảng vuông gồm nn hàng và nn cột. Các hàng được đánh số từ 1 đến nn, các cột được đánh số từ 1 đến nn. Ở ô hàng thứ ii và cột thứ jj có giá trị là i×j (1i,jn)i \times j \ (1 \leq i,j \leq n).

Yêu cầu

Cho một số nguyên dương xx. Hãy đếm số lượng ô trong bảng có giá trị bằng xx.

Dữ liệu

Vào từ tệp văn bản BS.INP: gồm hai số nguyên nnxx (1n106,1x1012)(1 \leq n \leq 10^6, 1 \leq x \leq 10^{12}) là kích thước của bảng và số nguyên cần đếm trong bảng.

Kết quả

Ghi ra tệp văn bản BS.OUT: số nguyên duy nhất là số lượng ô trong bảng có giá trị bằng xx.

Ràng buộc

  • Có 70% số test ứng với 70% số điểm của bài thoả mãn 0<n103,1x1060 < n \leq 10^3, 1 \leq x \leq 10^6.
  • 30% số test còn lại ứng với 30% số điểm của bài không có ràng buộc gì thêm.

Ví dụ

BS.INPBS.OUT
6 52
6 124
5 130

Giải thích:

123456
24681012
369121518
4812162024
51015202530
61218243036

Lời giải

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int main()
{
    ll n, x, ans = 0;
    cin >> n >> x;
    for (int i = 1; i <= n; i++)
    {
        if (x % i != 0 || x < i)
            continue;
        if (x / i <= n)
            ans++;
    }
    cout << ans;
    return 0;
}

Bài 3. Chia tiền thưởng

Nhờ hoàn thành tốt công việc, An và Bình được công ty thưởng NN tờ tiền.

Tờ tiền thứ ii có mệnh giá aia_i. Hai bạn muốn chia đôi số tiền thành hai phần bằng nhau bằng cách chia cho mỗi người một số tờ tiền. Vì thế hai bạn quyết định sẽ chọn ra những tờ tiền để tổng số tiền hai bạn nhận được bằng nhau và lớn nhất, phần còn lại (nếu có) sẽ đem đi đầu tư.

Yêu cầu

Hãy giúp hai bạn tìm tổng số tiền lớn nhất mà mỗi người nhận được trước khi đầu tư.

Dữ liệu

Vào từ tệp văn bản CT.INP:

  • Dòng đầu tiên chứa số nguyên dương N (N500)N \ (N\leq 500).
  • Dòng thứ hai bao gồm NN số nguyên dương a1,a2,...,aNa_1, a_2, ..., a_N là mệnh giá của những tờ tiền. Tổng giá trị những tờ tiền sẽ không vượt quá 10510^5.

Kết quả

Ghi ra tệp văn bản CT.OUT: gồm một dòng duy nhất là số tiền lớn nhất mà mỗi người nhận được.

Ràng buộc

  • Có 40% số test ứng với 40% số điểm của bài thoả mãn N3N \leq 3.
  • 30% số test tiếp theo ứng với 30% số điểm của bài thoả mãn N12N \leq 12.
  • 30% số test còn lại ứng với 30% số điểm của bài không có ràng buộc gì thêm.

Ví dụ

CT.INPCT.OUTGiải thích
5
1 2 4 5 2
7An có thể chọn những tờ tiền có mệnh giá 1, 2, 4.
Bình sẽ chọn tờ tiền có mệnh giá 5, 2.
Mỗi người sẽ nhận được tổng số tiền là 7.
Không còn tiền để đi đầu tư.
5
9 8 4 5 13
17An sẽ chọn những tờ tiền có mệnh giá 9, 8.
Bình sẽ chọn tờ tiền có mệnh giá 4, 13.
Mỗi người sẽ nhận được tổng số tiền là 17.
Tờ tiền có mệnh giá 5 sẽ đem đi đầu tư.

Lời giải

Ý tưởng

Mục tiêu của ta là tìm ra số tiền lớn nhất mà mỗi người có được sau khi chia tiền với tiêu chí là 2 người đều có số tiền như nhau, nghĩa là số tiền còn lại mang đi đầu tư là nhỏ nhất và số tiền chênh lệch giữa họ là bằng 0.

Ý tưởng là ta sẽ bắt đầu tính toán khi số tiền chênh lệch giữa 2 người là lớn nhất, và lần lượt giảm số tiền chênh lệch đó đi đến khi bằng 0.

Gọi:

  • jj là số tiền chênh lệch giữa 2 người.
  • m[i]m[i] là giá trị tờ tiền thứ ii.

Tại vị trí (i,j)(i,j), khi mà số tiền chênh lệch giữa 2 người là jj, và công ty mới chỉ thưởng cho 2 người đến tờ tiền thứ ii, thì ta quan tâm việc mỗi người được nhiều nhất bao nhiêu tiền sau khi chia. Nói cách khác, số tiền để lại mang đi đầu tư nhỏ nhất là bao nhiêu.

Ta định nghĩa dp[i][j]dp[i][j] là số tiền nhỏ nhất để lại.

Hiển nhiên rằng, số tiền chênh lệch giữa 2 người không thể lớn hơn tổng số tiền mà công ty đã thưởng. Vì vậy ta cần thêm một giá trị nữa, p[i]p[i], tổng số tiền từ tờ thứ 11 đến ii.

Khi xét đến tờ thứ ii tại số tiền chênh lệch jj:

  • Nếu j>p[i]j > p[i] (số tiền chênh lệch lớn hơn cả tổng số tiền công ty thưởng), vậy thì sự chênh lệch đó không tồn tại:

    dp[i][j]= dp[i][j] = \infty
  • Nếu j=p[i]j = p[i] (số tiền chênh lệch bằng tổng số tiền công ty thưởng), vậy thì một người sẽ không có số tiền nào và người kia sẽ có toàn bộ số tiền:

    dp[i][j]=0 dp[i][j] = 0
  • Trường hợp còn lại:

    • Hai người quyết định để lại tờ tiền thứ ii để đầu tư:

      dp[i][j]=dp[i1][j]+m[i] dp[i][j] = dp[i-1][j] + m[i]
    • Ngược lại, ta lại có 2 lựa chọn:

      1. Tờ tiền thứ ii thuộc về người đang có ít tiền hơn:

        dp[i][j]=dp[i1][abs(jm[i])] dp[i][j] = dp[i-1][\text{abs}(j-m[i])]
      2. Tờ tiền thứ ii thuộc về người đang có nhiều tiền hơn, và tất nhiên số tiền chênh lệch sau đó vẫn không thể vượt quá được tổng số tiền tính đến tờ thứ ii:

        dp[i][j]=dp[i1][j+m[i]] dp[i][j] = dp[i-1][j+m[i]]

    ⇒ Vậy giá trị tốt ưu nhất là giá trị nhỏ nhất trong 3 giá trị trên.

Kết quả của bài toán chính là tổng số tiền trừ đi dp[n1][0]dp[n-1][0] và chia cho 2.

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define nl '\n'
#define inf 1e18

int main()
{
    int n;
    cin >> n;
    vector<ll> m(n), p(n);
    for (int i = 0; i < n; i++)
    {
        cin >> m[i];
        p[i] = (i == 0 ? m[i] : p[i - 1] + m[i]);
    }

    vector<vector<ll>> dp(n, vector<ll>(p[n - 1] + 1));
    fill(dp[0].begin(), dp[0].end(), inf);
    dp[0][0] = m[0];
    dp[0][m[0]] = 0;

    for (int i = 1; i < n; i++)
    {
        for (int j = p[n - 1]; j >= 0; j--)
        {
            if (j > p[i])
                dp[i][j] = inf;
            else if (j == p[i])
                dp[i][j] = 0;
            else
            {
                dp[i][j] = min(dp[i - 1][j] + m[i], dp[i - 1][abs(j - m[i])]);
                if (j + m[i] <= p[i])
                    dp[i][j] = min(dp[i][j], dp[i - 1][j + m[i]]);
            }
        }
    }
    p[n - 1] = (p[n - 1] - dp[n - 1][0]) / 2;
    cout << p[n - 1];
    return 0;
}

Bài 4. Trạm gác trung tâm

Ban quản lý rừng nguyên sinh đang quản lý một khu vực rộng lớn.

Họ đã xây dựng NN trạm canh gác rừng (được đánh số từ 1N1 \to N) và các trạm này được nối với nhau bởi MM con đường.

Trong NN trạm canh gác người ta đã chọn ra KK trạm làm trạm gác trung tâm - nơi điều hành các trạm gác nhỏ hơn và chứa các dụng cụ, phương tiện bảo vệ rừng.

Để đi lại và vận chuyển thiết bị dễ dàng giữa các trạm gác trung tâm, Ban quản lí quyết định nâng cấp một số con đường sao cho KK trạm gác trung tâm đều đi được đến nhau.

Yêu cầu

Hãy chọn các con đường nối KK trạm gác trung tâm để nâng cấp sao cho tổng độ dài của các con đường này là nhỏ nhất.

Dữ liệu

Vào từ tệp văn bản TG.INP:

  • Dòng đầu tiên ghi ba số nguyên dương N,M,KN, M, K lần lượt là số lượng các trạm gác, số lượng con đường nối giữa các trạm gác và số lượng các trạm gác trung tâm (1<N500;N1M<N2/2;1<KN)(1 < N \leq 500; N - 1 \leq M < N^2/2; 1 < K \leq N).
  • Dòng thứ hai ghi KK số nguyên là số hiệu của KK trạm gác trung tâm.
  • Trong MM dòng tiếp theo, mỗi dòng ghi ba số nguyên u,v,cu, v, c với ý nghĩa con đường hai chiều nối trực tiếp giữa hai trạm uuvv có độ dài là cc (1<c109)(1 < c \leq 10^9).

Kết quả

Ghi ra tệp văn bản TG.OUT: một dòng duy nhất chứa tổng độ dài các con đường thỏa mãn yêu cầu trên.

Ràng buộc

  • Có 40% số test ứng với 40% số điểm của bài thoả mãn K=N,N500K = N, N \leq 500.
  • 30% số test tiếp theo ứng với 30% số điểm của bài thoả mãn K10,N200K \leq 10, N \leq 200.
  • 30% số test còn lại ứng với 30% số điểm của bài không có ràng buộc gì thêm.

Ví dụ

TG.INPTG.OUTGiải thích
5 3 8
1 3 5
1 2 2
1 3 10
1 4 12
2 4 5
2 5 7
3 4 2
3 5 10
4 5 6
15Cần làm các con đường:
1 2
2 4
3 4
4 5
Tổng độ dài nhỏ nhất là: 15

Bài 5. Sắp xếp hoán vị

Cho số nguyên dương NN và dãy hoán vị từ 11 đến NN.

Hãy tính tổng chi phí nhỏ nhất để sắp xếp lại dãy con này thành dãy tăng dần.

Biết rằng có thể chọn một dãy con liên tiếp từ ii đến jj và sắp xếp lại dãy con này thành dãy tăng dần với chi phí là ji+1\lfloor \sqrt{j - i + 1} \rfloor (lấy phần nguyên, ví dụ 103=10\lfloor \sqrt{103} \rfloor = 10).

Dữ liệu

Vào từ tệp văn bản SX.INP:

  • Dòng đầu tiên chứa số nguyên dương NN (1N106)(1 \leq N \leq 10^6).
  • Dòng thứ hai chứa NN số nguyên dương là hoán vị từ 11 đến NN.

Kết quả

Ghi ra tệp văn bản SX.OUT: chỉ phí nhỏ nhất để sắp xếp dãy hoán vị đã cho thành dãy tăng dần.

Ràng buộc

  • Có 30% số test ứng với 30% số điểm của bài thoả mãn N9N \leq 9.
  • 30% số test tiếp theo ứng với 30% số điểm của bài thoả mãn N2000N \leq 2000.
  • 30% số test tiếp theo ứng với 30% số điểm của bài thoả mãn N105N \leq 10^5.
  • 10% số test còn lại ứng với 10% số điểm của bài thoả mãn N106N \leq 10^6.

Ví dụ

SX.INPSX.OUTGiải thích
5
3 1 4 2 5
2Chọn dãy con [3, 1] mất chi phí 1 và chuyển thành [1, 3, 4, 2, 5], sau đó chọn dãy con [3, 4, 2] với chi phí 1 để sắp xếp thành dãy [1, 2, 3, 4, 5] với tổng chi phí là 2.