2021暑假模拟赛4

A[CF1552A(800)]

本质上是求序列的不动点个数,也就是和最终排好序的序列相同的地方。

#include <bits/stdc++.h>
using namespace std;
int main() {
  int T;
  cin >> T;
  while (T --> 0) {
    int N;
    cin >> N;
    string S;
    cin >> S;
    string T(S);
    sort(T.begin(), T.end());
    int Ans = 0;
    for (int i = 0; i < N; ++i) {
      if (S[i] != T[i]) {
        Ans ++;
      }
    }
    cout << Ans << '\n';
  }
}
View Code

B[CF1110C(1500)]

观察一下容易得出如果$A$存在某一位为$0$,那么答案为将所有为$0$的位填满。如果不存在为$0$的位,那么需要从$A$中找一个子集使得子集是$A$的约数,枚举一下约数即可。

#include <bits/stdc++.h>
using namespace std;
int pre[] = {
1,
1,
5,
1,
21,
1,
85,
73,
341,
89,
1365,
1,
5461,
4681,
21845,
1,
87381,
1,
349525,
299593,
1398101,
178481,
5592405,
1082401};
int main() {
  int Q;
  cin >> Q;
  vector<int> A(Q);
  for (int i = 0; i < Q; ++i) {
    cin >> A[i];
  }
  for (int i = 0; i < Q; ++i) {
    int h = -1;
    for (int j = 0; j < 30; ++j) {
      if (A[i] >> j & 1) {
        h = j;
      }
    }
    int S = 0;
    for (int j = 0; j < h; ++j) {
      if (!(A[i] >> j & 1)) {
        S |= 1 << j;
      }
    }
    int Ans = 0;
    if (S == 0) {
      cout << pre[h - 1] << '\n';
    } else {
      Ans = (A[i] | S);
      cout << (A[i] | S) << '\n';
    }
  } 
}
View Code

C[1025B(1600)]

这个题的做法较多。由于求任意一个解即可,那么最方便的是找一个质因子。先求出所有$lcm(A_i,B_i)$的$gcd$,那么这里面肯定包含一个合法的质因子,于是枚举里面的质因子判断是否合法即可。

#include <bits/stdc++.h>
using namespace std;
vector<int> GetPrime(int n) {
  vector<bool> mark(n + 1);
  vector<int> Prime;
  for (int i = 2; i <= n; ++i) {
    if (!mark[i]) {
      Prime.emplace_back(i);
    }
    for (int j = 0; j < Prime.size() && i * Prime[j] <= n; ++j) {
      mark[i * Prime[j]] = true;
      if (i % Prime[j] == 0) {
        break;
      }
    }
  }
  return Prime;
}
int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  vector<int> P = GetPrime(100000);
  int N;
  cin >> N;
  vector<long long> A(N);
  vector<long long> B(N);
  for (int i = 0; i < N; ++i) {
    cin >> A[i] >> B[i]; 
  }
  long long g = 0;
  for (int i = 0; i < N; ++i) {
    long long C = A[i] / __gcd(A[i], B[i]) * B[i];
    g = __gcd(g, C);
  }
  for (int i : P) {
    if (g % i == 0) {
      cout << i << '\n';
      exit(0);
    }
  }
  vector<long long> ALL;
  for (auto i : A) {
    ALL.push_back(i);
  }
  for (auto i : B) {
    ALL.push_back(i);
  }
  for (auto i : ALL) {
    if (__gcd(i, g) >= 2) {
      cout << __gcd(i, g) << '\n';
      exit(0);
    }
  }
  cout << -1 << '\n';
}
View Code

D[CF1517D(1800)]

先观察出几个有用的性质:

1.去的路和返回的路肯定是一样的,否则不优

2.$k$必须为偶数,否则无法返回

由这两个性质可以把题目转化为求从任意一个点出发走$\frac{k}{2}$步的最远距离。考虑$dp[i][j][k]$表示走了$k$步,走到了$(i,j)$,转移枚举相邻的点走下一步即可。

#include <bits/stdc++.h>
using namespace std;
const long long Inf = numeric_limits<long long> :: max() / 3;
int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  int N, M, K;
  cin >> N >> M >> K;
  vector<vector<int>> A(N, vector<int> (M));
  for (int i = 0; i < N; ++i) {
    for (int j = 0; j < M - 1; ++j) {
      cin >> A[i][j];        
    }
  }
  vector<vector<int>> B(N, vector<int> (M));
  for (int i = 0; i < N - 1; ++i) {
    for (int j = 0; j < M; ++j) {
      cin >> B[i][j];
    }
  }
  if (K % 2 == 1) {
    for (int i = 0; i < N; ++i) {
      for (int j = 0; j < M; ++j) {
        cout << -1 << " \n"[j == M - 1];
      }
    }
    exit(0);
  }
  vector<vector<pair<int, int>>> adj(N * M);
  auto id = [&] (int X, int Y) -> int {
    return X * M + Y;
  };
  for (int i = 0; i < N; ++i) {
    for (int j = 0; j < M - 1; ++j) {
      adj[id(i, j)].emplace_back(id(i, j + 1), A[i][j]);
      adj[id(i, j + 1)].emplace_back(id(i, j), A[i][j]);
    }
  }
  for (int i = 0; i < N - 1; ++i) {
    for (int j = 0; j < M; ++j) {
      adj[id(i, j)].emplace_back(id(i + 1, j), B[i][j]);
      adj[id(i + 1, j)].emplace_back(id(i, j), B[i][j]);
    }
  }
  vector<vector<vector<long long>>> dp(N, vector<vector<long long>> (M, vector<long long> (K + 1, Inf)));
  for (int i = 0; i < N; ++i) {
    for (int j = 0; j < M; ++j) {
      dp[i][j][0] = 0;
    }
  }
  for (int k = 0; k < K / 2; ++k) {
    for (int i = 0; i < N; ++i) {
      for (int j = 0; j < M; ++j) {
        int X = id(i, j);
        for (auto [Y, W] : adj[X]) {
          int ii = Y / M;
          int jj = Y % M;
          dp[ii][jj][k + 1] = min(dp[ii][jj][k +1], dp[i][j][k] + W);
        }
      }
    }
  }
  for (int i = 0; i < N; ++i) {
    for (int j = 0; j < M; ++j) {
      cout << (dp[i][j][K / 2] == Inf ? -1 : dp[i][j][K / 2] * 2) << " \n"[j == M - 1];
    }
  }
}
View Code

 相信通过这几场比赛,大家肯定已经熟练掌握位运算以及分解质因数的操作了!

posted @ 2021-08-02 20:52  19992147  阅读(67)  评论(0编辑  收藏  举报