smu暑期集训第八次比赛题解

A.B - Savings

大致思路为求1到n的和,如果结果大于等于k救输出当前值

#include <iostream>
#include <algorithm>

using namespace std;

constexpr int N = 2010, M = 1010;

typedef long long ll;

char a[N][M];

void solve() {
    ll n;
    cin >> n;
    ll sum = 0;
    ll count = 0;
    for (ll i = 1; i <= n; i++) {
        sum += i;  // 计算当前的和
        if (sum >= n) {  // 如果和大于等于n
            cout << count + 1 << "\n";  // 输出结果(count加1)
            break;  // 跳出循环
        } else {
            count++;  // 否则,增加count的值
        }
    }
}

int main() {
    int t;
    //cin >> t;
    t = 1;
    while (t--) {
        solve();  // 调用solve函数
    }
}

B.C - abc285_brutmhyhiizp

该题可以转化为26进制转化为十进制

#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

constexpr int N = 2010, M = 1010;

typedef long long ll;


// 解决问题的函数
void solve() {
    string s;
    cin >> s;
    ll sum = 0;
    int n = s.size();
    for (int i = 0; i < s.size(); i++) {
        ll p = pow(26, n - i - 1); // 计算 26 的 n - i - 1 次幂
        sum += (s[i] - 'A' + 1) * p; // 将字符转换为对应的数值并乘以权值 p,然后累加到 sum
    }
    cout << sum << "\n"; // 输出结果
}

int main() {
    int t;
    //cin >> t; // 输入测试用例数量
    t = 1; // 假设只有一个测试用例
    while (t--) {
        solve(); // 调用解决问题的函数
    }
}

c.B - K-th Common Divisor

这道题目数据很小,可直接暴力从1跑到A与B的最小值

#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

constexpr int N = 2010, M = 1010;

typedef long long ll;

// 解决问题的函数
void solve() {
    int a, b, k;
    cin >> a >> b >> k; // 输入 a、b 和 k 的值
    int n = min(a, b); // 取 a 和 b 中的较小值作为循环的上界
    int count = 0; // 计数器,记录满足条件的个数
    for (int i = n; i >= 1; i--) {
        if (a % i == 0 && b % i == 0) { // 如果 i 是 a 和 b 的公约数
            count++; // 计数器加一
        }
        if (count == k) { // 如果计数器达到 k
            cout << i << "\n"; // 输出当前的公约数并结束函数
            return ;
        }
    }
}

int main() {
    int t;
    //cin >> t; // 输入测试用例数量
    t = 1; // 假设只有一个测试用例
    while (t--) {
        solve(); // 调用解决问题的函数
    }
}

D.C - Colorful Candies

该题是一道滑动窗口的题目,每一次的数量变化都与最后的那个值有关,可以借助哈希表来存储每一次滑动糖果颜色数量的值

#include <iostream>
#include <algorithm>
#include <cmath>
#include <map>

using namespace std;

constexpr int N = 3e5 + 10, M = 1010;

typedef long long ll;

int c[N];
map<int,int> mp, mp1;

// 解决问题的函数
void solve() {
    int n, k;
    cin >> n >> k; // 输入 n 和 k 的值
    int count = 0; // 计数器,记录不同元素的个数
    for (int i = 1; i <= n; i++) {
        cin >> c[i]; // 输入数组元素
        if (mp[c[i]] == 0) { // 如果当前元素还没有出现过
            count++; // 计数器加一
            mp[c[i]]++; // 标记当前元素已经出现过
        }
    }
    if (k == n) { // 如果 k 等于数组长度
        cout << count << "\n"; // 输出不同元素的个数并结束函数
        return ;
    }
    if (count == 1) { // 如果数组中只有一个不同的元素
        cout << 1 << "\n"; // 输出 1 并结束函数
        return ;
    }
    int sum = 0; // 记录最大不同元素个数
    for (int i = 1; i <= n; i++) {
        mp1[c[i]]++; // 将当前元素加入到临时计数器中
        if (i > k) { // 如果当前位置大于 k
            mp1[c[i - k]]--; // 从临时计数器中减去之前的元素
            if (mp1[c[i - k]] == 0) { // 如果之前的元素已经没有了
                mp1.erase(c[i - k]); // 从临时计数器中删除该元素
            }
        }
        int s = mp1.size(); // 统计临时计数器中不同元素的个数
        sum = max(s, sum); // 更新最大不同元素个数
    }
    cout << sum << "\n"; // 输出最大不同元素个数
}

int main() {
    int t;
    //cin >> t; // 输入测试用例数量
    t = 1; // 假设只有一个测试用例
    while (t--) {
        solve(); // 调用解决问题的函数
    }
}

E.D - Triangles

这个题目的数据有点水,直接暴力开三次方也可以过。他的正解则是找到其中两条边,第三条边可以通过二分来找到。

手写lower_bound:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>

using namespace std;

constexpr int N = 2e3 + 10, M = 1010;

typedef long long ll;

int n;
int a[N];

// 在区间 [l, r] 内寻找第一个大于等于 x 的元素的下标
int check(int l, int r, int x) {
    while(l <= r) {
        int mid = l + r >> 1; // 计算中间位置的索引
        if(a[mid] < x) {
            l = mid + 1; // 如果中间元素小于 x,更新左边界
        }
        else {
            r = mid - 1; // 否则更新右边界
        }
    }
    return l; // 返回第一个大于等于 x 的元素的下标
} 

void solve() {
    cin >> n; // 输入数组长度
    for (int i = 1; i <= n; i++) {
        cin >> a[i]; // 输入数组元素
    }
    sort(a + 1, a + n + 1); // 对数组进行升序排序
    ll count = 0; // 计数器,记录满足条件的对数
    for(int i = 1; i <= n; i++) {
        for(int j = i + 1; j <= n; j++) {
            int p = check(1, n, a[i] + a[j]); // 找到满足 a[i] + a[j] 的第一个元素的下标
            count += p - j - 1; // 更新计数器
        }
    }
    cout << count << "\n"; // 输出满足条件的对数
}

int main() {
    int t;
    t  = 1; // 假设只有一个测试用例
    //cin >> t; // 输入测试用例数量
    while (t--) {
        solve(); // 调用解决问题的函数
    }
    return 0;
}

直接用lower_band:

#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>

using namespace std;

int N = 3e5 + 10, M = 1010;

typedef long long ll;

int n;

vector<int> v;

// 解决问题的函数
void solve() {
    cin >> n; // 输入元素数量
    for (int i = 1; i <= n; i++) {
        int a;
        cin >> a; // 输入每个元素的值
        v.push_back(a); // 将元素加入 vector 容器
    }
    sort(v.begin(), v.end()); // 对 vector 容器中的元素进行升序排序
    ll count = 0; // 计数器,记录满足条件的对数
    for (int i = 0; i < n - 2; i++) {
        for (int j = i + 1; j < n - 1; j++) {
            // 使用二分搜索找到大于等于 v[i] + v[j] 的第一个元素
            auto it = lower_bound(v.begin(), v.end(), v[i] + v[j]);
            ll d = distance(it, v.end()); // 计算满足条件的元素个数
            count += (n - 1 - j) - d; // 更新计数器
        }
    }
    cout << count << "\n"; // 输出满足条件的对数
}

int main() {
    int t;
    t  = 1; // 假设只有一个测试用例
    //cin >> t; // 输入测试用例数量
    while (t--) {
        solve(); // 调用解决问题的函数
    }
    return 0;
}

F.C - Reorder Cards

该题使用的方法就是离散化加排序,对每一行,每一列进行排序。

#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>

using namespace std;

constexpr int N = 3e5 + 10, M = 1010;

struct number{
    int a;
    int b;
    int v1;
    int v2;
    int id;
}nu[N];

bool cmp(struct number x, struct number y) {
    return x.a < y.a;
}

bool cmp1(struct number x, struct number y) {
    return x.b < y.b;
}

bool cmp2(struct number x, struct number y) {
    return x.id < y.id;
}

void solve() {
    int h, w, n;
    cin >> h >> w >> n; // 输入矩阵的高度、宽度以及元素数量
    for (int i = 0; i < n; i++) {
        cin >> nu[i].a >> nu[i].b; // 输入每个元素的 a 值和 b 值
        nu[i].id = i + 1;
    }
    sort(nu, nu + n, cmp); // 根据 a 值对 nu 数组进行升序排序
    nu[0].v1 = 1;
    for (int i = 1; i < n; i++) {
        if (nu[i].a == nu[i - 1].a) {
            nu[i].v1 = nu[i - 1].v1; // 如果当前元素的 a 值与前一个元素的 a 值相等,则 v1 值也相等
        } else {
            nu[i].v1 = nu[i - 1].v1 + 1; // 否则,v1 值加一
        }
    }
    sort(nu, nu + n, cmp1); // 根据 b 值对 nu 数组进行升序排序
    nu[0].v2 = 1;
    for (int i = 1; i < n; i++) {
        if (nu[i].b == nu[i - 1].b) {
            nu[i].v2 = nu[i - 1].v2; // 如果当前元素的 b 值与前一个元素的 b 值相等,则 v2 值也相等
        } else {
            nu[i].v2 = nu[i - 1].v2 + 1; // 否则,v2 值加一
        }
    }
    sort(nu, nu + n, cmp2); // 根据 id 值对 nu 数组进行升序排序
    for (int i = 0; i < n; i++) {
        cout << nu[i].v1 << " " << nu[i].v2 << "\n"; // 输出每个元素的 v1 值和 v2 值
    }
}

int main() {
    int t;
    t = 1; // 设置 t 的值为 1
    while (t--) {
        solve();
    }
}

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值