vp 2025冬季PAT甲级

前言

考研初试刚结束不久,感觉初试考的不佳,为了面试有更高的分数,决定年后去考PAT甲级,于是今天vp了一下刚结束不久的2025冬季PAT甲级。总体来说,这场的强度不算大,没有卡各种算法和数据结构的时间复杂度,唯一值得说道的就是第一题的题目太长了,考的时候读题读的晕过去了。

题目总览

a4772b9256f24279cbd2cffe725c99ff

aaf977bf3d931efa8a9536e3e2575dab

题目细览

第1题 A-1 Auto-scaling

504aebe29d025d0439303734bc9b6b57

思路

题目很长,其实只看样例和提示就可以知道要我们干啥了,模拟一下即可。
先处理第二行要输出的答案C[i],前S-1个C[i]就是输入的c[i]本身,后续的C[i]就应该是前S个c[i]/T再累加起来(前S个中包含自己),这里我们可以使用滑动窗口或者前缀和来降低计算的复杂度,我这里用的是滑动窗口,具体实现见下方代码。
再考虑第一行要输出的答案,前s-1个答案就是max(1,C[i]/T),因为至少要使用一台服务器,后续的需要分类讨论,看(C[i]-C[i-s+1])/s是否大于等于T*2,若大于等于,那么答案应该是上一次的答案加上(C[i]-C[i-s+1])/(s*T),否则答案应该为max(1,C[i]/T)。因为有可能需要使用到上一次输出的答案,因此我们使用一个last变量来存上一次输出的答案,每次输出完当前答案,就更新一下last。

我的AC代码

#include <bits/stdc++.h>

using i64 = long long;

int main(){
  std::ios::sync_with_stdio(false);
  std::cin.tie(nullptr);
  std::cout.tie(nullptr);

  int n,T,S,s;
  std::cin >> n >> T >> S >> s;

  std::vector<int> c(n+1);
  for(int i = 1; i <= n; i++){
    std::cin >> c[i];
  }

  std::vector<int> C(n+1);
  int sum = 0;
  for(int i = 1; i <= S-1; i++){
    sum += c[i]/S;
  }
  for(int i = 1; i <= n; i++){
    if(i < S){
      C[i] = c[i];
    }else{
      sum += c[i]/S;
      sum -= c[i-S]/S;
      C[i] = sum;
    }
  }

  int last = -1;
  for(int i = 1; i <= n; i++){
    if(i < s){
      std::cout << std::max(1,C[i]/T) << " \n"[i==n];
      last = std::max(1,C[i]/T);
    }else{
      int diff = C[i]-C[i-s+1];
      int t = diff/s;
      if(t >= T*2){
        std::cout << "*" << last+diff/(s*T) << " \n"[i==n];
        last = last+diff/(s*T);
      }else{
        std::cout << std::max(1,C[i]/T) << " \n"[i==n];
        last = std::max(1,C[i]/T);
      }
    }
  }

  for(int i = 1; i <= n; i++){
    std::cout << C[i] << " \n"[i==n];
  }
}

第2题 A-2 Puzzle

f575ceb70ca0e8130d8454165ebd7495

思路

我们首先找到第一行第一列要填的数,然后从这个位置开始dfs,dfs中枚举四个方向,若没有越界且之前没有填好,那么就填上去,dfs结束后输出即可。而且,我们发现要找第一行第一列要填的数,只需要找某个数的left和up同时为0的数即可。

我的AC代码

#include <bits/stdc++.h>

using i64 = long long;

int main(){
  std::ios::sync_with_stdio(false);
  std::cin.tie(nullptr);
  std::cout.tie(nullptr);

  int n,m;
  std::cin >> n >> m;

  auto ans = std::vector(n+1,std::vector<int>(m+1));

  std::unordered_map<int,std::vector<int>> map;
  for(int i = 0; i < n*m; i++){
    int num;
    std::cin >> num;
    for(int j = 0; j < 4; j++){
      int x;
      std::cin >> x;
      map[num].push_back(x);
    }
  }

  std::vector<std::vector<bool>> vis(n+1,std::vector<bool>(m+1));
  for(auto [u,v]:map){
    if(v[0]==0 && v[2]==0){
      ans[1][1] = u;
      vis[1][1] = true;
      break;
    }
  }

  auto dfs = [&](auto &&self,int x,int y)->void {
    int num = ans[x][y];
    for(int i = 0; i < 4; i++){
      int to = map[num][i];
      if(to == 0){
        continue;
      }
      if(i == 0){
        if(vis[x-1][y]){
          continue;
        }
        ans[x-1][y] = to;
        vis[x-1][y] = true;
        self(self,x-1,y);
      }else if(i == 1){
        if(vis[x+1][y]){
          continue;
        }
        ans[x+1][y] = to;
        vis[x+1][y] = true;
        self(self,x+1,y);
      }else if(i == 2){
        if(vis[x][y-1]){
          continue;
        }
        ans[x][y-1] = to;
        vis[x][y-1] = true;
        self(self,x,y-1);
      }else{
        if(vis[x][y+1]){
          continue;
        }
        ans[x][y+1] = to;
        vis[x][y+1] = true;
        self(self,x,y+1);
      }
    }
  };

  dfs(dfs,1,1);

  for(int i = 1; i <= n; i++){
    for(int j = 1; j <= m; j++){
      std::cout << ans[i][j] << " \n"[j==m];
    }
  }
}

第3题 A-3 Network Security

04aa70d6337074d132894df085037ef8

思路

第一行要输出的答案其实就是出度(入度也可,因为是双向边,但出度在使用vector存邻接表时,可以直接用adj[i].size()来表示节点i的出度)最大的点按升序输出,因此我们只需要遍历一遍1~n,计算出出度最大值max,然后再遍历1~n,若出度等于max则输出。
第二行其实就是考虑不包含隔离服务器的并查集的数量。
后续不同的并查集根据所含的最小节点号升序输出即可,相同的并查集输出同时也按升序处理。

我的AC代码

#include <bits/stdc++.h>

using i64 = long long;

struct DSU{
  std::vector<int> f,sz;

  DSU(int n){
    f.resize(n+1);
    std::iota(f.begin(),f.end(),0);
    sz.assign(n+1,1);
  }

  int find(int x){
    if(f[x] != x){
      f[x] = find(f[x]);
    }
    return f[x];
  }

  bool merge(int u,int v){
    int fu = find(u);
    int fv = find(v);
    if(fu == fv){
      return false;
    }
    if(fv < fu){
      std::swap(fu,fv);
    }
    sz[fu] += sz[fv];
    f[fv] = fu;
    return true;
  }
};

int main(){
  std::ios::sync_with_stdio(false);
  std::cin.tie(nullptr);
  std::cout.tie(nullptr);

  int n,m;
  std::cin >> n >> m;

  std::vector<std::vector<int>> adj(n+1);
  std::vector<int> a(n+1);
  for(int i = 1; i <= n; i++){
    std::cin >> a[i];
  }

  for(int mi = 0; mi < m; mi++){
    int u,v;
    std::cin >> u >> v;
    adj[u].push_back(v);
    adj[v].push_back(u);
  }

  int max = 0;
  for(int i = 1; i <= n; i++){
    max = std::max(max,int(adj[i].size()));
  }

  bool isFirst = true;
  for(int i = 1; i <= n; i++){
    if(adj[i].size() == max && isFirst){
      std::cout << i;
      isFirst = false;
    }else if(adj[i].size() == max){
      std::cout << " " << i;
    }
  }
  std::cout << "\n";

  DSU dsu(n+1);
  for(int i = 1; i <= n; i++){
    if(a[i]){
      continue;
    }
    for(int j = 0; j < adj[i].size(); j++){
      if(a[adj[i][j]]){
        continue;
      }
      int findi = dsu.find(i);
      int findj = dsu.find(adj[i][j]);
      if(findi == findj){
        continue;
      }
      dsu.merge(findi,findj);
    }
  }

  std::map<int,std::vector<int>> map;

  for(int i = 1; i <= n; i++){
    if(a[i]){
      continue;
    }
    map[dsu.find(i)].push_back(i);
  }
  
  std::cout << map.size() << "\n";
  for(auto [u,v]:map){
    isFirst = true;
    for(int i = 0; i < v.size(); i++){
      if(isFirst){
        std::cout << v[i];
        isFirst = false;
      }else{
        std::cout << " " << v[i];
      }
    }
    std::cout << "\n";
  }
}

第4题 A-4 Prime Tree

ef91fc22f9953dc11aece07f84a9ec5b

思路

先来讲一下这个质数树的定义,对于深度为质数的节点,它的所有孩子节点数(这里它孩子的孩子也是它的孩子)也必须为质数,反之若深度不为质数,那么它的所有孩子节点数也必须不为质数。
因此,首先通过父亲为0找到根节点root,我们需要维护两个数组dep和son,分别表示节点的深度和它的所有孩子节点数,然后从根节点开始dfs,dfs中枚举边u->v,先令dep[v] = dep[u]+1,再dfs(v),最后累加孩子数son[u] = son[v]+1。
输出答案的时候,枚举i从1到n,依次输出i,dep[i],son[i]。然后判断dep[i]与son[i]的素性是否不同,若存在不同dep[i]和son[i]的素性,最后一行应该输出0,否则输出1。

我的AC代码

#include <bits/stdc++.h>

int main(){
  std::ios::sync_with_stdio(false);
  std::cin.tie(nullptr);
  std::cout.tie(nullptr);

  int n;
  std::cin >> n;

  std::vector<std::vector<int>> adj(n+1);
  int root = -1;
  for(int i = 1; i <= n; i++){
    int fa;
    std::cin >> fa;
    if(fa == 0){
        root = i;
    }
    adj[fa].push_back(i);
  }

  std::vector<int> dep(n+1),son(n+1);
  dep[root] = 1;

  auto dfs = [&](auto &&self,int u) ->void {
    for(auto v:adj[u]){
      dep[v] = dep[u]+1;
      self(self,v);
      son[u] += son[v]+1;
    }
  };
  
  dfs(dfs,root);

  bool isPrimeTree = true;

  auto isPrime = [&](int x){
    if(x < 2){
      return false;
    }
    for(int i = 2; i <= x/i; i++){
      if(x % i == 0){
        return false;
      }
    }
    return true;
  };

  for(int i = 1; i <= n; i++){
    std::cout << i << " " << dep[i] << " " << son[i] << "\n";
    bool isPrime1 = isPrime(dep[i]);
    bool isPrime2 = isPrime(son[i]);
    if((isPrime1&&!isPrime2) || (!isPrime1&&isPrime2)){
      isPrimeTree = false;
    }
  }
  std::cout << (isPrimeTree?1:0) << "\n";
}
posted @ 2026-01-04 21:09  Beau_Will  阅读(29)  评论(0)    收藏  举报