西华师范大学2025春季ACM集训队选拔赛(个人题解)

西华师范大学2025春季ACM集训队选拔赛

传送门

A - 水沝淼㵘

只需要找到输入的矩阵中的最大的三个值加起来看有没有超过 即可

#include <bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;

const int N = 1e5 + 5;

// struct ty {
// };

// bool cmp(ty a,ty b){
// }

void Solve(){
    int n;
    cin >> n;
    int k = n / 2;

    if (k <= 3) {
        cout << "YES";
        return ;
    }

    int mx1 = 0, mx2 = 0, mx3 = 0;
    int num;

    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            cin >> num;
            if (num > mx1) {
                mx3 = mx2;
                mx2 = mx1;
                mx1 = num;
            } else if (num > mx2) {
                mx3 = mx2;
                mx2 = num;
            } else if (num > mx3) {
                mx3 = num;
            }
        }
    }

    int sum = mx1 + mx2 + mx3;
    cout << (sum >= k ? "YES" : "NO");

	return ;
}

int main(){

	int T = 1;
	// cin >> T;

	while(T--){
		Solve();
	}

	return 0;
}

B - Excel大神

字母表一共有 \(26\) 个英文字母,我们可以把它当做 \(26\) 进制来计算。 比如: \(A\) 就是 \(0\) 一直到 \(Z\)\(25\) 。 那么现在就会有一个问题,题目规定的是从 \(1\) 开始。所以说我们每次计算的时候把 \(n\) 自减,这样就对上了。 所以最主要的做法就是将输入的 \(n\)\(10\) 进制转换成 \(26\) 进制。

#include <bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;

const int N = 1e5 + 5;

// struct ty {
// };

// bool cmp(ty a,ty b){
// }

void Solve(){
    ll n;
    cin >> n;
    string str;

    while (n > 0) {
    	n--;
        int tmp = n % 26;
        str.push_back('a' + tmp);
        n /= 26;
    }

    reverse(str.begin(), str.end());
    cout << str << endl;

	return ;
}

int main(){

	int T = 1;
	// cin >> T;

	while(T--){
		Solve();
	}

	return 0;
}

C - 圣杯

快速幂求逆元模版题。 题目样例解释已经告诉了解法了,只需要对答案的分数进行取模。 分数取模其实很简单,就是分子乘分母的逆元就行了。 但是需要注意计算次方的时候不能一个一个的乘,会超时,直接使用快速幂计算次方

#include <bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;

const int MOD = 1e9 + 7;
ll pre1, pre2;

// struct ty {
// };

// bool cmp(ty a,ty b){
// }

ll kpow(ll b, ll ex) {
    ll ret = 1;
    b %= MOD;
    while (ex > 0) {
        if (ex % 2 == 1) {
            ret = (ret * b) % MOD;
        }
        b = (b * b) % MOD;
        ex /= 2;
    }
    return ret;
}

void pre() {
    pre1 = kpow(100, MOD - 2);
    pre2 = (pre1 * pre1) % MOD;

    return ;
}

void Solve(){
	int n, p, q;
    scanf("%d%d%d", &n, &p, &q);
    ll b = (2LL * p * q) % MOD;
    b = b * pre2 % MOD;
    ll ans = kpow(b, n);
    printf("%lld\n", ans);

	return ;
}

int main(){
	pre();
	int T = 1;
	scanf("%d",&T);

	while(T--){
		Solve();
	}

	return 0;
}

D - 正方形遍历

直接打表,要形成欧拉回路的必要条件就是每个节点的度数要为偶数,因此所有的 \(n\) 都符合这个条件,所以全是 \(Yes\)

差不多规律就是这样,然后连边欧拉回路

#include <bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;

const int N = 1e3 + 5;

// struct ty {
// };

// bool cmp(ty a,ty b){
// }

void Solve(){
    int n;
    cin >> n;
    
    vector<vector<pair<int, int>>> e(N);
    vector<bool> vis(N);
    n++;
    int idx = 0;
    vector<bool> no(N);
    no[n] = true;
    for (int i = 1; i <= n - 1; i++) {
        no[n + (n - 1) * i] = true;
    }

    auto add = [&](int u, int v) -> void {
        e[u].push_back({v, idx});
        e[v].push_back({u, idx++});
    };
    // 连横边
    for (int i = 0; i < n; i++) {
        for (int j = 1; j < n; j++) {
            add(n * i + j, n * i + j + 1);
        }
    }
    // 连竖边
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < n - 1; j++) {
            add(n * j + i, n * (j + 1) + i);
        }
    }
    // 连斜边
    for (int i = 0; i < n - 1; i++) {
        for (int j = 1; j <= n; j++) {
            int now = n * i + j;
            int nxt = now + n - 1;
            if (!no[now] && now != n * i + 1) {
                add(now, nxt);
            }
        }
    }
    vector<int> ans;
    // 欧拉回路
    auto dfs = [&](auto &&self, int u) -> void {
        for (auto [v, id]: e[u]) {
            if (vis[id]) {
                continue;
            }
            vis[id] = true;
            self(self, v);
        }
        ans.push_back(u);
    };
    dfs(dfs, 1);
    cout << "Yes" << endl;
    for (auto t : ans) {
        cout << t << " ";
    }

    return ;
    }

    int main(){

    int T = 1;
    // cin >> T;

    while(T--){
        Solve();
    }

	return 0;
}

E - 参加比赛

#include <bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;

const int N = 1e5 + 5;
int n;
vector<int> scr(N);
vector<int> dp(N, 0);
// struct ty {
// };

// bool cmp(ty a,ty b){
// }

void Solve(){

    cin >> n;
    scr.resize(n);
    for (int i = 0; i < n; ++i) {
        cin >> scr[i];
    }

    dp.resize(n+2, 0);

    for (int i = n - 1; i >= 0; --i) {
        int x = scr[i];
        int nxt = x + 1;
        int cur = 1 + dp[nxt];
        if (cur > dp[x]) {
            dp[x] = cur;
        }
    }

    return ;
}

void Ret(){
	int x;
    cin >> x;
    cout << dp[x] << endl;

	return ;
}

int main(){

	Solve();

	int T = 1;
	cin >> T;

	while(T--){
		Ret();
	}

	return 0;
}

F - 字符串


G - 质数排列

题目要求我们索引为 \(i\) 的数对应的值 \(a_i\) 同为质数或者同为不是质数。 那直接让 \(i=a_i\) 就满足所有条件了。 所以直接输出 $i $ ~ $ n$ 。

#include <iostream>
using namespace std;

int main() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cout << i << " ";
    }
    return 0;
}

H - 一闪一闪亮晶晶

结论不难,就是相同的为一组,直接用 \(set\) 统计就行,接下来给出证明。 我们首先记 \(b_min = min(b_1,b_2,...,b_m)\)\(b_max=(b_1,b_2,...,b_m)\) 已知 \(gcd(b1,b2,...,b_m)\leq b_{min}\) ,最大公约数的性质,\(gcd(a,b)\leq min(a,b)\) ,又因为 \(b_1\&b_2\&...\&b_m\leq b_{min}\) ,与运算的性质,\(a\&b\leq min(a,b)\), 故左边\(\leq 2\times b_{min}\) ,又因为右边 \(= 2\times b_{max}\) 左边要等于右边 ,左边取最大的可能 \(2\times b_{min}\) 得到了这个等式:\(2\times b_{min} = 2\times b_{max}\) 要使等式成立,则必须要求 \(b_{min} = b_{max}\) 。 ,所以同一组的星星必须亮度完全相同才行

#include <bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;

const int N = 1e5 + 5;

// struct ty {
// };

// bool cmp(ty a,ty b){
// }

void Solve(){
    int n;
    cin >> n;
    unordered_set<int> a;
    
    for (int i = 0; i < n; ++i) {
        int tmp;
        cin >> tmp;
        a.insert(tmp);
    }
    
    cout << a.size() << endl;

    return ;
}

int main(){

    int T = 1;
    cin >> T;

    while(T--){
        Solve();
    }

    return 0;
}

I - 快乐风男

要求的是至少发生一起争吵的方案。 至少发生一起争吵方案的对立事件就是完全不发送争吵。 那么我们知道,完全不发生争吵,就是所有人的出装都一样才行,那么这样的方案数只可能有 \(m\) 种。 所以我们可以用所有的方案减去完全不发生争吵的方案。 所有的方案就是每个人都有 \(m\) 种出装方式,即 \(m^n\)。 故答案就是 \(m^n-m\),需要对\(10^9 + 7\) 取模,所以 \(m^n\) 用快速幂计算即可。 注意 \(m^n\) 取模后可能比 \(m\) 小,这样就成负数了,所以我们要加个 \(mod\) 再取模。

#include <bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;

const int MOD = 1e9 + 7;

// struct ty {
// };

// bool cmp(ty a,ty b){
// }

ll pmod(ll b, ll ex, ll mod) {
    ll ret = 1;
    b %= mod;
    while (ex > 0) {
        if (ex % 2 == 1) {
            ret = (ret * b) % mod;
        }
        b = (b * b) % mod;
        ex /= 2;
    }
    return ret;
}

void Solve(){
	ll m, n;
    cin >> m >> n;
    
    ll tat = pmod(m, n, MOD);
    ll xt = m % MOD;
    ll ans = (tat - xt + MOD) % MOD;
    
    cout << ans << endl;

	return ;
}

int main(){

	int T = 1;
	// cin >> T;

	while(T--){
		Solve();
	}

	return 0;
}

J - 无量仙翁的救赎


K - 你是天命人吗


L - K距离


M - 火炎焱燚

根据题意模拟即可,注意死亡后移动不会拾取碎片,所以需要一个变量来记录当前是生还是死

#include <bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;

const int N = 1e5 + 5;

// struct ty {
// };

// bool cmp(ty a,ty b){
// }

void Solve(){
int n, m;
    cin >> n >> m;
    vector<vector<int>> a(n + 1, vector<int>(n + 1, 0));
    
    for (int i = 0; i < m; ++i) {
        int x, y, z;
        cin >> x >> y >> z;
        a[x][y] = z;
    }
    
    bool live = 1;
    int curx = 0, cury = 0;
    int f = 0;
    
    for (int i = 0; i < n; ++i) {
        string op;
        cin >> op;
        if (op == "M") {
            int x, y;
            cin >> x >> y;
            curx = x;
            cury = y;
            if (live) {
                f += a[x][y];
                a[x][y] = 0;
            }
        } else if (op == "D") {
            int dop = f / 2;
            if (curx >= 1 && curx <= n && cury >= 1 && cury <= n) {
                a[curx][cury] += dop;
            }
            f = 0;
            live = 0;
        } else if (op == "R") {
            live = 1;
            curx = 0;
            cury = 0;
            f = 0;
        }
    }
    
    int tat = 0;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            tat += a[i][j];
        }
    }
    
    cout << f << " " << tat << endl;

	return ;
}

int main(){

	int T = 1;
	// cin >> T;

	while(T--){
		Solve();
	}

	return 0;
}
posted @ 2025-03-03 08:03  Zyihan_Crz  阅读(27)  评论(0)    收藏  举报