2024-XTU程设练习1部分题解

1531-奇怪的数字

思路:模拟即可

#include <iostream>
#include <vector>
#include <string>

int main()
{
    int n = 1000000;
    for (int i = 100;i <= n;i++) {
        std::string s = std::to_string(i);
        std::vector<int>mp(10, 0);
        for (auto& ss : s) {
            mp[ss - '0']++;
        }
        for (auto& ss : s) {
            int num = ss - '0';
            if (num == 0) continue;
            std::vector<int>mp1 = mp;
            if (i % num == 0) {
                int nextNum = i / num;
                //std::cout << i << " " << num << " " << nextNum << std::endl;
                std::string st = std::to_string(nextNum);
                mp1[num]--;
                for (auto& sst : st) {
                    mp1[sst - '0']--;
                }
            }
            bool is = false;
            for (auto& m : mp1) {
                if (m != 0) {
                    is = true;
                    break;
                }
            }
            if (!is) {
                printf("%d\n", i);
                break;
            }
        }
    }
    return 0;
}

1542-数列

思路:模拟+哈希表
我们不难看出生成的数列如果遇到重复的,说明数列生成完成,将生成的所以数用哈希表存储,然后再遍历m寻找未存储的数

#include <stdio.h>
#include <string.h>

int main()
{
    int n;
    scanf("%d", &n);

    while (n--) {
        long long a, b, m, s = 0;
        scanf("%lld%lld%lld", &a, &b, &m);
        //哈希表
        int mp[100001];
        mp[0] = 1;
        memset(mp, 0, sizeof(mp));
        //遇到重复的就推出
        while (!mp[(a * s + b) % m]) {
            s = (a * s + b) % m;
            mp[s] = 1;
        }
        //你也可以从1遍历到m
        for (int i = 1;i <= 1e5 + 1;i++) {
            if (!mp[i]) {
                printf("%d\n", i);
                break;
            }
        }
    }
    return 0;
}

1548-回文串

思路:你可以将每个地方数字插进去寻找规律。
例如 [ 1 , 2 , 3 , 4 , 5 ] ,当你插入 X 到 2 后面的时候为 [ 1 , 2 , X , 3 , 4 , 5 ] 那么要求 [ X , 3 ] 是回文串 [ 1 , 2......4 , 5 ] 也得是回文串 例如[1,2,3,4,5],当你插入X到2后面的时候为 \\ [1,2,X,3,4,5]那么要求[X,3]是回文串\\ [1,2......4,5]也得是回文串 例如[1,2,3,4,5],当你插入X2后面的时候为[1,2,X,3,4,5]那么要求[X,3]是回文串[1,2......4,5]也得是回文串

#include <iostream>
#include <string>
#include <vector>

using namespace std;

int main()
{
    string s;
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    //取消同步流
    while (cin >> s) {
        int n = s.size(), ans = 0;
        if (n == 1) {
            cout << 2 << '\n';
            continue;
        }
        vector<vector<bool>>mp(n + 1, vector<bool>(n + 1, false));
        bool isOk = true;

        for(int i = n / 2;i <= n - 2;i++) {
            mp[n - 2 - i][i] = (isOk && s[i] == s[n - 2 - i]);
            isOk = mp[n - 2 - i][i];
        }
        isOk = true;
        for (int i = n / 2; i >= 1;i--) {
            mp[i][n - i] = (isOk && s[i] == s[n - i]);
            isOk = mp[i][n - i];
        }
        if (!(n & 1)) mp[n / 2 - 1][n / 2 - 1] = true;
        /*for (int i = 0;i <= n;i++) {
            for (int j = 0;j <= n;j++) {
            cout << i << " " << j << " " << mp[i][j] << " " << '\n';
            }
        }*/
        for (int i = 0;i <= n / 2;i++) {
            int l = i - 1, r = n - i;
            bool left = true, right = true;
            if (l >= 0 && r >= 0 && (s[l] != s[r])) right = false;
            if (i <= n / 2 - 1 && !mp[i][n - 2 - i]) left = false;
            if (left && right) ans++;
            else if(!right)break;
        }
        int m = n / 2 + 1;
        if (!(n & 1)) m = n / 2;
        for (int i = 1; i <= m;i++) {
            int l = i - 2, r = n - i + 1;
            bool left = true, right = true;
            if (l >= 0 && r >= 0 && (s[l] != s[r])) right = false;
            if (i <= n / 2 && !mp[i][n - i]) left = false;
            if (left && right) ans++;
            else if(!right)break;
        }
        cout << ans << '\n';
    }
    return 0;
}

1549-2的幂次 I

思路:二分。找到一个然后二分找第二个。
时间复杂度为 t n l o g n tnlogn tnlogn
这里插一嘴,C++有二分的API,所以多用API。

#define  _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

int count_pairs_with_power_of_2(vector<int>& S) {
    int n = S.size();
    int pairs_count = 0;
    for (int i = 0; i < n; ++i) {
        for (int k = 1; k <= 30; ++k) {
            int target = (1 << k) - S[i];
            if (target < 0) continue;
            if (binary_search(S.begin() + i + 1, S.end(), target)) {
                pairs_count++;
            }
        }
    }
    return pairs_count;
}

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        int n;
        scanf("%d", &n);
        vector<int> S(n);
        for (int i = 0; i < n; ++i) {
            scanf("%d", &S[i]);
        }
        printf("%d\n", count_pairs_with_power_of_2(S));
    }
    return 0;
}

1553-数字

太简单了No Code。

1559-奇偶数位

太简单了No Code。

1575-四位数

太简单了No Code。

1530-game

思路:先把所有的数据一次性读完然后再处理,不如你不知道哪个是最后一行。

#define  _CRT_SECURE_NO_WARNINGS
#include <vector>
#include <algorithm>
#include <string>
#include <iostream>

using namespace std;


int main() {
    int source, game = 1, index = 0;
    bool is = false;
    string a, b, c, d;
    vector<string>names = { "Alice", "Bob" };
    vector<int>goals(2);
    vector<int>sources;
    vector<string>as, bs, cs, ds;
    while (cin>>source>>a>>b>>c>>d) {
        sources.push_back(source);
        as.push_back(a);
        bs.push_back(b);
        cs.push_back(c);
        ds.push_back(d);
    }
    cout << "Alice start game 1" << endl;
    for (int i = 0;i < sources.size();i++) {
        if (as[i] == "PAPER") sources[i] -= 5;
        if (bs[i] == "PAPER") sources[i] -= 5;
        if (cs[i] == "PAPER") sources[i] -= 5;
        if (ds[i] == "PAPER") sources[i] -= 5;
        if (sources[i] == 0) {
            goals[index]++;
            cout << names[index] + " win game " << game << endl;
            if (i == sources.size() - 1) {
                break;
            }
            cout << names[index] + " start game " << ++game << endl;
        }
        else {
            index = abs(index - 1);
            if (i == sources.size() - 1) {
                break;
            }
            cout << "Change to " + names[index] << endl;
        }
    }
    cout << "Game over " << goals[0] << ":" << goals[1] << endl;
    return 0;
}

1538-打字机

思路:C++使用Vector模拟即可,还可以使用链表,我推荐用现成的Vector。

1539-区间

思路:滑动窗口。
使用滑动窗口, L e f t 和 R i g h t ,如果去掉这一个 区间还是大于 K ,那么就是区间小了, R i g h t 右 移动 ; 否则 L e f t 左移查看有无更小的答案 时间复杂度 O ( t m n ) 其中 m = 26 对应 26 个字母。 使用滑动窗口,Left和Right,如果去掉这一个\\区间还是大于K,那么就是区间小了,Right右\\移动;\\否则Left左移查看有无更小的答案\\时间复杂度O(tmn)\\其中m=26对应26个字母。 使用滑动窗口,LeftRight,如果去掉这一个区间还是大于K,那么就是区间小了,Right移动;否则Left左移查看有无更小的答案时间复杂度O(tmn)其中m=26对应26个字母。

#include <vector>
#include <limits.h>
#include <string>
#include <iostream>

using namespace std;

bool isOk(string& s, vector<int>& mp, int k) {
    for (auto& m : mp) {
        if (m > k) {
            return false;
        }
    }
    return true;
}

int main() {
    int t = 0;
    cin >> t;
    while (t--) {
        int k, j = 0, ans = INT_MAX;
        string s;
        cin >> k >> s;
        vector<int>mp(26, 0);
        int n = s.size();
        for (auto& ss : s) {
            mp[ss - 'a']++;
        }
        for (int i = 0;i < n;i++) {
            while (j < n && !isOk(s, mp, k)) {
                mp[s[j] - 'a']--;
                j++;
            }
            if (j <= n && isOk(s, mp, k) && j >= i) {
                ans = min(ans, j - i);
            }
            mp[s[i] - 'a']++;
        }
        ans = ans == INT_MAX ? 0 : ans;
        cout << ans << endl;
    }
    return 0;
}

1541-卷积

未写

1547-圆

本来是100的通过率现在只有80了(doge

1576-分段

思路:模拟,我们可以先求出n的公因数,例如当n=16时,你能分成1,2,4,8段,然后分别求每一段的值,然后比较大小,你也可以排序之后从段最大的算起,比较段大的值肯定越小,其中 n = 1 e 5 顶天好像也就 50 还是 75 个公因数,还是能过 时间复杂度为 O ( n n l o g n ) n=1e5顶天好像也就50还是75个公因数,还是能过\\时间复杂度为O(\sqrt{n} nlogn) n=1e5顶天好像也就50还是75个公因数,还是能过时间复杂度为O(n nlogn)

#define  _CRT_SECURE_NO_WARNINGS
#include <vector>
#include <algorithm>
#include <cmath>
#include <stdio.h>

using namespace std;


int main() {
    long long n, sums = 0;
    scanf("%lld", &n);
    vector<long long>nums(n);
    vector<long long>counts;
    for (int i = 0;i < n;i++) {
        scanf("%lld", &nums[i]);
        sums += nums[i];
    }
    for (long long i = 1;i <= sqrt(sums)+10;i++) {
        if (sums % i == 0) {
            counts.push_back(i);
            counts.push_back(sums / i);
        }
    }
    sort(counts.begin(), counts.end());
    for (int j = counts.size() - 1;j >= 0;j--) {
        long long c = counts[j], sum = 0, p = sums / c;
        bool is = true;
        for (int i = 0;i < nums.size();i++) {
            sum += nums[i];
            if (sum == p) {
                sum = 0;
            }
            else if (sum > p) {
                is = false;
                break;
            }
        }
        if (is) {
            printf("%lld\n", p);
            break;
        }
    }
    return 0;
}

1583-彩球

思路:也是滑动窗口,注意再左移右移的时候看哈希表能否满足条件即可。

#define  _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <algorithm>
#include <vector>

using namespace std;


int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        int m, n, k, p = 0;
        scanf("%d%d%d", &n, &m, &k);
        vector<int>arrs(n + 1);
        vector<int>mp(n + 2, 0);
        for (int i = 0;i < n;i++) {
            scanf("%d", &arrs[i]);
        }
        arrs[n] = 0;
        for (int i = 0;i < m;i++) {
            if (mp[arrs[i]] == 0) {
                p++;
            }
            mp[arrs[i]]++;
        }
        int left = 0, right = m - 1;
        bool isOk = true;
        while (right < n) {
            if (p != k) {
                isOk = false;
                break;
            }
            else {
                int l = arrs[left], r = arrs[right + 1];
                mp[l]--;
                if (mp[l] == 0) {
                    p--;
                }
                mp[r]++;
                if (mp[r] == 1) {
                    p++;
                }
                left++, right++;
            }
        }
        if (isOk) {
            printf("Yes\n");
        }
        else {
            printf("No\n");
        }
    }
    return 0;
}

1484-刷油漆

思路:逆推,我们可以想学最后一个刷了之后,如果是列,那么前面的所有的行的颜色是不是肯定会少一个?倒数第二个如果也是和前面不同的列,那么前面的行的颜色是不是就会少两个?以此类推。

#include <cstdio>
#include <vector>

using namespace std;


int main() {
    int n, m, c, t;
    scanf("%d %d %d %d", &n, &m, &c, &t);
    vector<bool>row(n, false), cow(m, false);
    vector<int>colors(c + 1);
    vector<vector<int>>operation(t, vector<int>(3));

    for (int i = 0; i < t; ++i) {
        for (int j = 0;j < 3;++j) {
            scanf("%d", &operation[i][j]);
        }
    }
    for (int i = t - 1;i >= 0;--i) {
        if (n == 0 || m == 0) break;
        int f = operation[i][0], l = operation[i][1], k = operation[i][2];
        if (f == 0) {
            if (!row[l - 1]) {
                colors[k] += n;
                m--;
                row[l - 1] = true;
            }
        }
        else {
            if (!cow[l - 1]) {
                colors[k] += m;
                n--;
                cow[l - 1] = true;
            }
        }
    }

    for (int i = 1; i <= c; ++i) {
        if (colors[i] > 0) {
            printf("%d %d\n", i, colors[i]);
        }
    }
    return 0;
}

1556-和

二维前缀和的模板题,上网去学习一个什么是二位前缀和就能做了,这里不放代码。

1560-平方数

这位更是重量级。
令 x 2 + b x + c = ( x + a ) 2 化简得 x = a 2 − c b − 2 a 令x^2+bx+c = (x+a)^2 化简得x=\frac{a^2-c}{b-2a} x2+bx+c=(x+a)2化简得x=b2aa2c
接下来就容易了,从公式不难看出,a的最大值就是 ( c ) \sqrt(c) ( c),并且a绝对是大于0的。

#include <stdio.h>
#include <vector>
#include <algorithm>

using namespace std;


int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        int b, c;
        scanf("%d%d", &b, &c);
        vector<int> ans;
        if (4 * c == b * b) {
            printf("-1\n");
            continue;
        }
        for (int i = 1e4;i >= 0;--i) {
            if ((b != 2 * i) && (i * i - c) % (b - 2 * i) == 0) {
                int p = (i * i - c) / (b - 2 * i);
                if (p > 0) {
                    //cout << i << endl;
                    ans.push_back(p);
                }
            }

        }
        if (ans.empty()) {
            printf("0\n");
        }
        else {
            sort(ans.begin(), ans.end());
            for (int i = 0; i < ans.size() - 1; i++) {
                printf("%d ", ans[i]);
            }
            printf("%d\n", ans.back());
        }
    }
    return 0;
}

1567-3个矩形与1个正方形

这个也是个重量级。
思路:我们不难知道,三面积和是正方形的和,那么三个矩形的所有边肯定有一条边是正方形的边长,因此我们先找到这个矩形,然后将他作为基点,其实后面就是求剩下的两个矩形是否能组合成一个符合要求的长方形,这个长方形能和基点矩形组合成为正方形。

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

using namespace std;

bool compareSecond(const vector<long long>& a, const vector<long long>& b) {
    return a[1] < b[1];
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        long long sum = 0;
        vector<vector<long long>>grid(3, vector<long long>(2));
        for (int i = 0;i < 3;i++) {
            for (int j = 0;j < 2;j++) {
                scanf("%lld", &grid[i][j]);
            }
        }
        for (int i = 0;i < 3;i++) {
            sum += grid[i][0] * grid[i][1];
            sort(grid[i].begin(), grid[i].end());
        }
        sort(grid.begin(), grid.end(), compareSecond);
        long long p = sqrt(sum);
        if (p * p != sum) {
            printf("No\n");
        }
        else {
            long long a = grid[0][0], b = grid[0][1], c = grid[1][0], d = grid[1][1], e = grid[2][0], f = grid[2][1];
            if (f == p) {
                long long g = f - e;
                bool is = false;
                if (a == c && b + d == f && a == g) {
                    is = true;
                }
                if (a == d && a == g && b + d == f) {
                    is = true;
                }
                if (b == c && b == g && a + d == f) {
                    is = true;
                }
                if (b == d) {
                    if (b == f && a + c == g) {
                        is = true;
                    }
                    else if (b == g && a + c == f) {
                        is = true;
                    }
                }
                if (!is) {
                    printf("No\n");
                }
                else{
                    printf("Yes\n");
                }
            }
            else {
                printf("No\n");
            }
        }
    }
    return 0;
}

1578

未写

1565

未写

总结

总感觉你们的程设练习是越来越难了,当年我们的练习一都是模
拟,公式题,你们这一就开始双指针二分,还有二维前缀和,可
能也是越来越卷了吧。在oj看到刷题数排名21和22届占比最多,
我们当时都没人愿意刷ojhhhh

“请多上战场,您若长居幕后,从有一天会忘了生命之贵重”

  • 19
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值