六题七题尾铜,七题手速银,八题前排九题金
D:签到
// Code Start Here
int n;
cin >> n;
int n1 = n , n2 = 0;
while(n)n2 += n%10 , n /= 10;
if( ((int)(sqrt(n1))) * ((int)(sqrt(n1))) == n1 && ((int)(sqrt(n2))) * ((int)(sqrt(n2))) == n2)cout <<"Yes" << endl;
else cout <<"No" <<endl;
H:
很好玩的一个题,题目也重点强调了“可达”这个概念,这个题有一个结论,就是1~n的所有点一定是联通的,所以直接输出区间长度即可
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
#define point(x) fixed << setprecision(x)
#define sz(x) ((int)(x.size()))
template <typename T> inline void debug(T x){cout <<"this is ---> " << x << endl;}
int32_t main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
// Code Start Here
int t;
cin >> t;
while(t--){
int s , l , r;
cin >> s >> l >> r;
cout << r - l + 1 << endl;
}
return 0;
}
J:签到 暴力循环26次取最大值即可
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
#define point(x) fixed << setprecision(x)
#define sz(x) ((int)(x.size()))
template <typename T> inline void debug(T x){cout <<"this is ---> " << x << endl;}
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};
int32_t main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
// Code Start Here
string s;
cin >> s;
int max_val = 0;
for(int i = 0;i<=26;i++){
int now = 0;
for(int j = 0;j<sz(s);j++){
now += holes_cnt[((int)(s[j]-'A'+i)%26)];
}
max_val = max(max_val , now);
}
cout << max_val << endl;
return 0;
}
M:判断联通可以使用并查集动态维护,最后再看一下连通块的数量
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
#define point(x) fixed << setprecision(x)
#define sz(x) ((int)(x.size()))
template <typename T> inline void debug(T x){cout <<"this is ---> " << x << endl;}
struct DSU {
vector<int> fa, p, e, f;
DSU(int n) {
fa.resize(n + 1);
iota(fa.begin(), fa.end(), 0);
p.resize(n + 1, 1);
e.resize(n + 1);
f.resize(n + 1);
}
int get(int x) {
while (x != fa[x]) {
x = fa[x] = fa[fa[x]];
}
return x;
}
bool merge(int x, int y) { // 设x是y的祖先
if (x == y) f[get(x)] = 1;
x = get(x), y = get(y);
e[x]++;
if (x == y) return false;
if (x < y) swap(x, y); // 将编号小的合并到大的上
fa[y] = x;
f[x] |= f[y], p[x] += p[y], e[x] += e[y];
return true;
}
bool same(int x, int y) {
return get(x) == get(y);
}
bool F(int x) { // 判断连通块内是否存在自环
return f[get(x)];
}
int size(int x) { // 输出连通块中点的数量
return p[get(x)];
}
int E(int x) { // 输出连通块中边的数量
return e[get(x)];
}
};
int32_t main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
// Code Start Here
int n , m;
cin >> n >> m;
DSU q(n);
int ans = 0;
for(int i = 1;i<=m;i++){
int u , v;
cin >> u >> v;
if(q.same(u , v))ans++;
q.merge(u , v);
}
set<int> st;
for(int i = 1;i<=n;i++)st.insert(q.get(i));
cout << ans + sz(st) - 1 << endl;
return 0;
}
G:
一种比较容易想到的方法是分奇偶讨论,如下图
可以发现只有4是没答案的
然后直接模拟就可以了
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
#define point(x) fixed << setprecision(x)
#define sz(x) ((int)(x.size()))
template <typename T> inline void debug(T x){cout <<"this is ---> " << x << endl;}
int32_t main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
// Code Start Here
int t;
cin >> t;
while(t--){
int n;
cin >> n;
if(n == 4)cout <<"-1" << endl;
else if(n == 2)cout << 1 << " " <<2 << endl;
else {
if(n % 2 == 1){
for(int i = 1;i<(n + 3)/2;i++)cout << i << " " << i + 1 << endl;
int idx = (n + 3)/2+1;
for(int i = 2;i<=(n + 3)/2-2;i++)cout << i << " " << idx++ <<endl;
}
else{
for(int i = 1;i<(n + 4)/2;i++)cout << i << " " << i + 1 << endl;
int idx = (n + 4)/2+1;
for(int i = 2;i<=(n + 4)/2-3;i++)cout << i << " " << idx++ <<endl;
}
}
}
return 0;
}
F:
首先想到最优的情况是一旦走到终点联通的地方,马上停止药效,所以对于终点先跑一个BFS判断联通
其次思考对于如何去取最短的路径,第一想法是对于起点的连通块全部跑一遍BFS,但是时间复杂度不可行,其次思考如何优化,注意到最优的情况是一旦走到边界(即紧挨着#)才会使用药,所以取边界点,时间复杂度约为O((n + m) n *m) 不太可取
最后再思考怎么优化,对于起点跑一遍bfs,当越过边界(紧挨着#)的时候,在这个基础上++dis,最后判断什么时候到达终点,dijk也可取,时间复杂度为O(n * m )或者O(n * m * lognm)
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
#define point(x) fixed << setprecision(x)
#define sz(x) ((int)(x.size()))
template <typename T> inline void debug(T x){cout <<"this is ---> " << x << endl;}
int dx[] = {-1 , 0 , 1 , 0};
int dy[] = {0 , 1 , 0 , -1};
int32_t main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
// Code Start Here
int t;
cin >> t;
while(t--){
int n , m;
cin >> n >> m;
auto inbound = [&](int x , int y){
return x >= 0 && y < m && y >= 0 && x < n;
};
vector<vector<char>> g(n , vector<char>(m));
for(int i = 0;i<n;i++){
for(int j = 0;j<m;j++){
cin >> g[i][j];
}
}
auto bfs = [&](int x, int y)->vector<vector<int>>{
vector<vector<int>> dis(n, vector<int>(m, INT_MAX));
vector<vector<bool>> vis(n, vector<bool>(m,false));
vector<pair<int, int>> p;
queue<pair<int, int>> q;
q.push({x, y});
vis[x][y] = true;
while (!q.empty()) {
auto [x_, y_] = q.front();
q.pop();
p.emplace_back(x_, y_);
for (int i = 0; i < 4; i++) {
int nx = x_ + dx[i], ny = y_ + dy[i];
if (inbound(nx, ny) && !vis[nx][ny] && g[nx][ny] == '.') {
vis[nx][ny] = true;
q.push({nx, ny});
}
}
}
for (auto [x, y] : p) {
dis[x][y] = 0;
q.push({x, y});
}
while (!q.empty()) {
auto [x_, y_] = q.front();
q.pop();
for (int i = 0; i < 4; i++) {
int nx = x_ + dx[i], ny = y_ + dy[i];
if (inbound(nx, ny) && dis[nx][ny] == INT_MAX) {
dis[nx][ny] = dis[x_][y_] + 1;
q.push({nx, ny});
}
}
}
return dis;
};
vector<vector<int>> dis0 = bfs(0, 0);
vector<vector<int>> dis1 = bfs(n - 1, m - 1);
int ans = INT_MAX;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
ans = min(ans, dis0[i][j] + dis1[i][j] - 1);
}
}
cout << max(ans , 0) << endl;
}
return 0;
}
E:
字符串排序 + 贪心配对
我们无法预知哪些是“引”、哪些是“根”,但最终要组成 n 对。所以不如直接将所有 2n 个字符串按字典序排序。然后每两个字符串分为一组(偶数是「引」,奇数是「根」)。因为字典序相近的字符串,公共前缀更可能更长。
int n;
cin >> n;
vector<string> a(2 * n);
for (int i = 0; i < 2 * n; i++) cin >> a[i];
sort(a.begin(), a.end());
for (int i = 0; i < 2 * n; i++) {
if (i % 2 == 0) {
int v = 0;
for (char c : a[i]) {
int v = c - 'a';
if (!ch[v][v]) ch[v][v] = idx++;
v = ch[v][v];
}
}
}
i64 ans = 0;
for (int i = 0; i < 2 * n; i++) {
if (i % 2 == 1) {
int v = 0;
int res = 0;
for (char c : a[i]) {
int v = c - 'a';
if (!ch[v][v]) break;
v = ch[v][v];
res++;
}
ans += res;
}
}
cout << ans << endl;