西华师范大学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;
}