Problem D. 2025
题目:
思路:
签到
模拟即可 ,不多解释
代码:
#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"
bool check(int x)
{
int q = sqrt(x);
if (q * q != x)
{
return false;
}
return true;
}
void solve()
{
int y;
cin >> y;
if (!check(y))
{
no;
return;
}
int x = 0;
while (y)
{
x += y % 10;
y /= 10;
}
if (!check(x))
{
no;
return;
}
yes;
}
signed main()
{
cin.tie(0)->sync_with_stdio(false);
int t = 1;
while (t--)
{
solve();
}
return 0;
}
Problem J. Ring Trick
题目:
思路:
签到
模拟即可
代码:
#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"
int holes_cnt[26] = { 1, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
void solve()
{
string s;
cin >> s;
int ans = 0;
for (int k = 0; k < 26; k++)
{
int temp = 0;
for (int i = 0; i < s.size(); i++)
{
temp += holes_cnt[(s[i] - 'A' + k) % 26];
}
ans = max(ans, temp);
}
cout << ans << endl;
}
signed main()
{
cin.tie(0)->sync_with_stdio(false);
int t = 1;
while (t--)
{
solve();
}
return 0;
}
Problem F. 幻形之路
题目:
思路:
BFS + 思维
题目说我们可以开一次桂使得我们可以连续穿墙 k 步,求最小 k
这里注意是连续穿墙 k 步,而不是有 k 步能穿墙,所以我们不能简单的BFS
我们这里可以采用一个双向BFS的想法,我们分别从起点和终点出发,看看什么时候哪些点会碰到墙,这里BFS两遍即可,同时储存这些下一步就要碰墙的点
然后如果不能直接到,那么就要穿墙,此时我们直接从两个集合中暴力枚举即可,最后取一个最小距离即可(不过居然没超时,我们应该是要将两个集合再进行一次BFS,此时以前者为源点集合,后者为终点集合)
代码:
#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"
pair<int, int> dir[4] = { {1,0},{-1,0},{0,-1},{0,1} };
void solve()
{
int n, m;
cin >> n >> m;
vector<vector<char>> mp(n + 1, vector<char>(m + 1, 0));
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> mp[i][j];
}
}
vector<vector<int>> vis(n + 1, vector<int>(m + 1, 0));
queue<pair<int, int>> q,q2;
q.push({ 1,1});
q2.push({ m,n });
set<pair<int, int>> fromS, fromE;
while (!q.empty())
{
auto t = q.front();
q.pop();
int x = t.first;
int y = t.second;
if (x == m && y == n)
{
cout << "0\n";
return;
}
if (vis[y][x])
{
continue;
}
vis[y][x] = 1;
for (int i = 0; i < 4; i++)
{
int newx = x + dir[i].second;
int newy = y + dir[i].first;
if (newx < 1 || newy < 1 || newx > m || newy > n)
{
continue;
}
if (mp[newy][newx] == '#')
{
fromS.insert({ y,x });
continue;
}
q.push({newx,newy});
}
}
while (!q2.empty())
{
auto t = q2.front();
q2.pop();
int x = t.first;
int y = t.second;
if (vis[y][x])
{
continue;
}
vis[y][x] = 1;
for (int i = 0; i < 4; i++)
{
int newx = x + dir[i].second;
int newy = y + dir[i].first;
if (newx < 1 || newy < 1 || newx > m || newy > n)
{
continue;
}
if (mp[newy][newx] == '#')
{
fromE.insert({ y,x });
continue;
}
q2.push({ newx,newy });
}
}
int ans = 1e9;
for (auto& p1:fromS)
{
for (auto & p2 : fromE)
{
ans = min(ans, abs(p1.first - p2.first) + abs(p1.second - p2.second) - 1);
}
}
cout << ans << endl;
}
signed main()
{
cin.tie(0)->sync_with_stdio(false);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
Problem H. 树论函数
题目:
思路:
观察 or 猜测
这里直接猜测得出来,我们可以计算前几个值,如 1 2,2 3,3 4,发现这几对都能连接到一个节点上,所以猜测相邻的两个节点可以连接到同一个父节点上,即所有节点都能互通
(其实看数据也应该知道要往是否有结论上猜)
代码:
#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"
void solve()
{
int s, l, r;
cin >> s >> l >> r;
cout << r - l + 1 << endl;
}
signed main()
{
cin.tie(0)->sync_with_stdio(false);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
Problem M. 川陀航空学院
题目:
思路:
DFS + 思维
题目告诉我们最后要连成一颗树,那么显然一共只需要 n - 1条边,所以我们可以直接暴力遍历所有边,看看那些边是有效的,设其为 cnt(有效即代表这条边连的点之前未走过,因为我们只需要访问一遍即可,多次访问肯定是重复的,即多余的)
那么我们就要删去 m - cnt 条边,同时要增加 n - 1 - cnt 条边,因此答案就是 n-1-cnt + m-cnt
特别的,由于给定的图不一定是联通的,所以我们要遍历所有节点来DFS
代码:
#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"
vector<vector<int>> g(1000005);
vector<int> vis(1000006,0);
int cnt = 0;
void dfs(int fa,int se)
{
vis[se] = 1;
for (auto & son : g[se])
{
if (son == fa || vis[son]) continue;
dfs(se, son);
cnt++;
}
}
void solve()
{
int n, m;
cin >> n >> m;
for (int i = 0; i < m; i++)
{
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
for (int i = 1; i <= n; i++)
{
if (!vis[i])
{
dfs(i, i);
}
}
int need = n - 1;
cout << (need - cnt) + (m - cnt) << endl;
}
signed main()
{
cin.tie(0)->sync_with_stdio(false);
int t = 1;
while (t--)
{
solve();
}
return 0;
}
Problem G. 直径与最大独立集
题目:
思路:
思维 + 构造
结论:只要 n 不为 4 就能构造出来,具体方法如下图

没啥讲的,手画找规律即可
代码:
#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"
void solve()
{
int n;
cin >> n;
if (n == 4)
{
cout << "-1\n";
return;
}
if (n == 2)
{
cout << "1 2\n";
return;
}
int flag = 0;
if (n % 2 == 0)
{
n--;
flag = 1;
}
int need = (n - 3) / 2;
for (int i = 1; i < 3 + need; i++)
{
cout << i << " " << i + 1 << endl;
}
if (flag)
{
cout << 3 + need << " " << n+1 << endl;
}
int fa = 2, start = 3 + need + 1;
for (int i = 0; i < need; i++)
{
cout << start++ << " " << fa++ << endl;
}
}
signed main()
{
cin.tie(0)->sync_with_stdio(false);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
Problem E. 双生魔咒
题目:
思路:
贪心 + 字典树
题解没看懂,但是我会贪(猜)
我们先按照字典序排好,贪心的想,因为按照字典序排序,那么这样就能保证相邻的字符串前缀更多,此时我们按照奇偶顺序来分配 根 和 引 一定是最优的
然后套用字典树加一点小更改即可,先把奇数的放进字段数,然后偶数的进行查询
(复习字典树)
代码:
#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
#include <complex>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"
int idx = 0;
int cnt[1000000];
int tire[100005][26];
int ans = 0;
void insert(const string& s)
{
int p = 0;
for (auto &c : s)
{
if (!tire[p][c])
{
tire[p][c] = ++idx;
}
p = tire[p][c];
cnt[p]++;
}
}
void query(const string& s)
{
int p = 0;
for (auto& c : s)
{
if (!tire[p][c])
{
return;
}
p = tire[p][c];
ans += cnt[p];
}
}
void solve()
{
int n;
cin >> n;
vector<string> s(2 * n);
for (int i = 0; i < 2*n; i++)
{
cin >> s[i];
}
sort(s.begin(), s.end());
for (int i = 0; i < 2*n; i+=2)
{
insert(s[i]);
}
for (int i = 1; i < 2*n; i+=2)
{
query(s[i]);
}
cout << ans << endl;
}
signed main()
{
cin.tie(0)->sync_with_stdio(false);
int t = 1;
while (t--)
{
solve();
}
return 0;
}


&spm=1001.2101.3001.5002&articleId=149236234&d=1&t=3&u=c4eabf62ebc0416db1ea4d842540abe6)
1820

被折叠的 条评论
为什么被折叠?



