寒假acm集训第一讲笔记

寒假acm集训第一讲笔记

题目网址:https://vjudge.net/article/7420


第一题 Long Loong

很简单的循环语句,没啥好说的。

#include <iostream>
using namespace std;
int main()
{
    int N;
    cin >> N;
    cout << "L";
    for (int i = 0; i < N; i++)
    {
        cout << "o";
    }
    cout << "ng";
    return 0;
}

第二题 YES or YES?

首先因为char类型本质是int类型,用ASCII码把大小写统一,然后判断即可。

#include <iostream>
using namespace std;
int main()
{
    int t;
    cin >> t;
    char s[5];
    for (int i = 0; i < t; i++)
    {
        cin >> s;
        for (int j = 0; j < 3; j++)
        {
            if (s[j] >= 97 && s[j] <= 122)
                s[j] -= 32;
        }
        if (s[0] == 'Y' && s[1] == 'E' && s[2] == 'S')
            cout << "YES" << endl;
        else
            cout << "NO" << endl;
    }
    return 0;
}

第三题 Even? Odd? G

奇偶性只需要判断个位数即可,而且题目给的数据范围是每个正整数不超过10^60,明显不是一般的int或long long能够处理的,所以我们先以字符串形式输入,然后用strlen得到字符串长度后,找到个位的那个字符,同样利用char类型本质是int类型(ASCII码),再判断个位是否偶数即可。

#include <iostream>
#include <string.h>
using namespace std;
int main()
{
    int n;
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        char s[63];
        cin >> s;
        int a;
        int L = strlen(s);
        a = s[L - 1] - '0';
        if (a % 2 == 0)
            cout << "even" << endl;
        else
            cout << "odd" << endl;
    }
    return 0;
}

第四题 Problem Generator

有m轮,那么'A'、'B'、'C'、'D'、'E'、'F'和'G'就分别要有m个,我使用count [ i ] (i = 0 ~ 6)来分别表示'A'、'B'、'C'、'D'、'E'、'F'和'G'还需要提出多少次,初始化均为m。

接下来每输入一个字母,在保证count [ i ] 不会出现负数的情况下,count [ i ] --

最后用sum累加count [ i ] 即可。

#include <iostream>
#include <string.h>
using namespace std;
int main()
{
    int t;
    cin >> t;
    for (int i = 0; i < t; i++)
    {
        int n, m;
        cin >> n >> m;

        int count[7];
        for (int k = 0; k < 7; k++)
            count[k] = m;

        char s[55];
        cin >> s;
        for (int j = 0; j < n; j++)
        {
            if (count[s[j] - 'A'] > 0)
                count[s[j] - 'A']--;
        }

        int sum = 0;
        for (int h = 0; h < 7; h++)
            sum += count[h];
        cout << sum << endl;
    }
    return 0;
}

第五题 rules

用num_k记录某一天遵守规则k的人数
用count记录规则k符合名意的天数

另外注意判断条件是“大于等于一半”,所以奇偶数要分开计算

其余没啥好说的。

#include <iostream>
#include <string.h>
using namespace std;
int main()
{
    int n, m, k, count = 0;
    cin >> n >> m >> k;

    for (int i = 0; i < m; i++)
    {
        int num_k = 0;
        for (int j = 0; j < n; j++)
        {

            int a;
            cin >> a;
            if (a == k)
                num_k++;
        }
        if (n % 2 == 0)
            if (num_k >= n / 2)
                count++;
        if (n % 2 != 0)
            if (num_k > n / 2)
                count++;
    }

    if (m % 2 == 0)
    {
        if (count >= m / 2)
            cout << "YES";
        else
            cout << "NO";
    }
    if (m % 2 != 0)
    {
        if (count > m / 2)
            cout << "YES";
        else
            cout << "NO";
    }
    return 0;
}

第六题 Many Replacement

  1. 存储所有操作
    • 先把所有操作 ((c_i, d_i)) 读取并保存下来,不要立刻在字符串上做替换。
  2. 倒序构造 finalMap
    • finalMap[x] 表示字母 'a' + x 最后会被替换成哪个字母(以整数 0~25 表示,0 对应 'a',1 对应 'b',…)。
    • 初始时 finalMap[x] = x,表示所有字母默认保持自己。
    • 从后往前遍历操作:
      • 如果本次操作是“将 c 替换成 d”,那么我们就让 finalMap[c] = finalMap[d]。这样等价于 “c 的最终去向 = d 的最终去向”。
  3. 一次性替换字符串
    • 遍历字符串的每个字符,根据 finalMap 把它映射成“最终字符”,得到结果后输出。

时间复杂度:

  • 构造 finalMap 阶段,遍历 (Q) 次操作,每次操作 (O(1)),合计 (O(Q))。
  • 最终替换字符串,遍历 (N) 个字符,合计 (O(N))。
  • 总体 (O(N + Q)),足以应对 (N, Q \leq 2\times 10^5) 的规模。
#include <bits/stdc++.h>
using namespace std;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N, Q;
    cin >> N;

    string S;
    cin >> S;

    cin >> Q;
    // 用于记录 Q 次操作
    vector<pair<char, char>> ops(Q);
    for (int i = 0; i < Q; i++)
    {
        char c, d;
        cin >> c >> d;
        ops[i] = {c, d};
    }

    // finalMap[x] 表示字母 x(0~25) 最终会被替换成哪个字母(0~25)
    // 初始情况下,每个字母都映射为它自己
    vector<int> finalMap(26);
    iota(finalMap.begin(), finalMap.end(), 0);
    // 相当于 for (int i=0; i<26; i++) finalMap[i] = i;

    // 从后往前处理操作
    for (int i = Q - 1; i >= 0; i--)
    {
        char c = ops[i].first;  // 被替换的字母
        char d = ops[i].second; // 替换成的字母
        // 注意把字符转成 0~25 的数字
        int ic = c - 'a';
        int id = d - 'a';
        // 让 'c' 的最终指向 = 'd' 的最终指向
        finalMap[ic] = finalMap[id];
    }

    // 最后遍历字符串,按照 finalMap 映射
    for (int i = 0; i < N; i++)
    {
        int x = S[i] - 'a';    // 当前字符对应的索引
        int nx = finalMap[x];  // 它最终要变成的字母索引
        S[i] = char(nx + 'a'); // 映射回字符
    }

    cout << S << "\n";
    return 0;
}


第七题 更好的交换(比较长)

1、初次题解

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

int main()
{
    int n, m, a[102][102], row[102], col[102]; // row行column列
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
            cin >> a[i][j];
    }

    for (int i = 1; i <= n; i++)
    {
        row[i] = i;
        col[i] = i;
    }

    for (int i = 0; i < m; i++)
    {
        int op, x, y;
        cin >> op >> x >> y;
        if (op == 0) // 列
        {
            int t;
            t = col[x];
            col[x] = col[y];
            col[y] = t;
        }
        if (op == 1) // 行
        {
            int t;
            t = row[x];
            row[x] = row[y];
            row[y] = t;
        }
    }

    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            cout << a[row[i]][col[j]] << " ";
        }
        cout << endl;
    }

    return 0;
}

虽然已经用了懒惰映射,但是运行超时了

2、修改后AC代码

后来加了两行提高效率的代码,并且把数组设成[n+1][n+1]就行了

#include <iostream>
using namespace std;

int main()
{
    // 加这两行能提高运行效率
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m;
    cin >> n >> m;
    int a[n + 1][n + 1], row[n + 1], col[n + 1]; // row行column列
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
            cin >> a[i][j];
    }

    for (int i = 1; i <= n; i++)
    {
        row[i] = i;
        col[i] = i;
    }

    for (int i = 0; i < m; i++)
    {
        int op, x, y;
        cin >> op >> x >> y;
        if (op == 0) // 列
            swap(col[x], col[y]);
        if (op == 1) // 行
            swap(row[x], row[y]);
    }

    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            cout << a[row[i]][col[j]] << " ";
        }
        cout << endl;
    }

    return 0;
}

后面我也问了问gpt,也贴上来吧

3、gpt代码

代码分析

时间复杂度分析:

  1. 输入数据处理:

    • 读取矩阵 a 的时间复杂度为 ( O(n^2) )。
    • 读取并初始化 rowcol 数组的复杂度为 ( O(n) )。
    • 总计:( O(n^2 + n) \approx O(n^2) )。
  2. 操作处理:

    • 进行 m 次操作,每次交换数组元素,交换操作为 ( O(1) )。
    • 总计:( O(m) )。
  3. 输出结果:

    • 遍历输出矩阵,时间复杂度为 ( O(n^2) )。

综合时间复杂度:
[ O(n^2) + O(m) + O(n^2) = O(n^2 + m) ]
如果 ( m ) 非常大,可能会影响性能,但最主要的时间消耗仍在矩阵遍历阶段。


空间复杂度分析:

  1. 矩阵 a 需要 ( O(n^2) ) 空间。
  2. rowcol 数组分别需要 ( O(n) ) 空间。
  3. 变量 op, x, y 等需要常数 ( O(1) ) 空间。

综合空间复杂度:
[ O(n^2 + n) \approx O(n^2) ]
矩阵存储占据主要空间。


优化建议

  1. 减少输出矩阵遍历:

    • 目前代码在输出时按照 row[i]col[j] 进行两次索引,这导致随机访问影响性能。可以考虑直接修改矩阵或延迟索引计算以减少查询次数。
  2. 使用懒惰映射 (Lazy Mapping):

    • 通过记录行列的映射,避免真正交换,直接按映射顺序输出。该方案已经在代码中使用,但进一步减少查询时的索引操作开销可以提高性能。
  3. 优化输入输出 (I/O 优化):

    • 替换 cin / coutscanf / printfios::sync_with_stdio(false); cin.tie(0); 以加快输入输出处理。
  4. 减少矩阵访问:

    • 若只需要查询特定行列而非完整矩阵输出,可尝试仅在查询时计算映射关系,避免存取整个矩阵。

改进代码示例:

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

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n, m;
    cin >> n >> m;
    vector<vector<int>> a(n + 1, vector<int>(n + 1));
    vector<int> row(n + 1), col(n + 1);

    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
            cin >> a[i][j];
    }

    iota(row.begin(), row.end(), 0);
    iota(col.begin(), col.end(), 0);

    for (int i = 0; i < m; i++)
    {
        int op, x, y;
        cin >> op >> x >> y;
        if (op == 0)
            swap(col[x], col[y]);
        else
            swap(row[x], row[y]);
    }

    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            cout << a[row[i]][col[j]] << " ";
        }
        cout << '\n';
    }

    return 0;
}

优化点:

  • 使用 vector 代替数组,提高可读性与灵活性。
  • 使用 iota 快速初始化行列数组。
  • 添加 ios::sync_with_stdio(false); cin.tie(0); 以提高 I/O 性能。

结论

  • 时间复杂度优化目标:
    将整体保持在 ( O(n^2 + m) ),减少不必要的矩阵访问。

  • 空间复杂度优化目标:
    由于矩阵本身必须存储,无法降低到 ( O(n) ),但可减少额外的辅助空间使用。

按照以上建议,能够在大数据输入情况下减少运行时间并避免超时问题。

最后,感谢观看~

posted @ 2025-01-23 22:51  yesno233233  阅读(24)  评论(0)    收藏  举报