2021暑假模拟赛10

A[CF1497A(800)]

可以发现从小到大排序后$mex$最大,于是排序后统计即可。

#include <bits/stdc++.h>
using namespace std;
int main() {
  int T;
  cin >> T;
  while (T --) {
    int N;
    cin >> N;
    vector<int> A(N);
    for (int i = 0; i < N; ++i) {
      cin >> A[i];
    }
    vector<int> cnt(101);
    for (int i = 0; i < N; ++i) {
      cnt[A[i]] ++;
    }
    vector<int> Ans;
    for (int i = 0; i < 101; ++i) {
      if (cnt[i] > 0) {
        cnt[i] --;
        Ans.push_back(i);
      }
    }
    for (int i = 0; i < 101; ++i) {
      for (int j = 0; j < cnt[i]; ++j) {
        Ans.push_back(i);
      }
    }
    for (int i = 0; i < N; ++i) {
      cout << Ans[i] << " \n"[i == N - 1];
    }
  }
  return 0;
}
View Code

B[CF1086B(1700)]

发现本质上直径肯定存在于两个叶子的路径上,于是把权值均匀地分布在叶子上可以使得答案最小。

#include <bits/stdc++.h>
using namespace std;
int main() {
  int N, S;
  cin >> N >> S;
  vector<vector<int>> adj(N);
  vector<int> d(N);
  for (int i = 0; i < N - 1; ++i) {
    int X, Y;
    cin >> X >> Y;
    X --;
    Y --;
    d[X] ++;
    d[Y] ++;
  }
  int D = 0;
  for (int i = 0; i < N; ++i) {
    if (d[i] == 1) {
      D ++;
    }
  }
  cout << fixed << setprecision(15);
  cout << ((long double)S / (long double)D * 2.) << '\n';
  return 0;
}
View Code

C[GYM103102D(1600)]

考虑一个区间$dp$,$dp[l][r]$表示区间$[l,r]$能获得的最大价值,转移枚举分割点即可。合并两个区间的代价预处理区间乘积即可。

#include <bits/stdc++.h>
using namespace std;
const int P = 1000003;
int main() {
    int N;
    cin >> N;
    vector<int> A(N);
    for (int i = 0; i < N; ++i) {
        cin >> A[i];
    }
    vector<vector<long long>> Mul(N, vector<long long> (N));
    for (int i = 0; i < N; ++i) {
        Mul[i][i] = A[i];
        for (int j = i; j + 1 < N; ++j) {
            Mul[i][j + 1] = 1LL * Mul[i][j] * A[j + 1] % P;
        }
    }
    vector<vector<long long>> dp(N, vector<long long> (N));
    for (int L = 1; L < N; ++L) {
        for (int i = 0; i + L < N; ++i) {
            int j = i + L;
            for (int k = i; k < j; ++k) {
                dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j] + (Mul[i][k] - Mul[k + 1][j]) * (Mul[i][k] - Mul[k + 1][j]));
            }
        }
    }
    cout << dp[0][N - 1] << '\n';
}
View Code

D[CF1497E1(1700)]

首先可以发现一个贪心,尽量把元素塞进当前区间,塞不进去开新的一段。那么问题在于如何判断塞进当前元素后是否合法,这里只需要判断是否存在完全平方数即可,那么等价于是否存在一个质因子的指数不为$0$且为偶数次。于是每次把元素暴力质因子分解,用$map$存储之前的质因子,判断即可。

#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(10000000);
  int T;
  cin >> T;
  while (T --) {
    int N, K;
    cin >> N >> K;
    vector<int> A(N);
    for (int i = 0; i < N; ++i) {
      cin >> A[i];
    }
    map<vector<int>, int> mp;
    int Ans = 0;
    for (int i = 0; i < N; ++i) {
      vector<int> F;
      for (int j : P) {
        if (j * j > A[i]) {
          break;
        }
        if (A[i] % j == 0) {
          int W = 0;
          while (A[i] % j == 0) {
            A[i] /= j;
            W ^= 1;
          }
          if (W == 1) {
            F.push_back(j);
          }
        }
      }  
      if (A[i] > 1) {
        F.push_back(A[i]);
      }
      sort(F.begin(), F.end());
      if (i == 0 || mp.find(F) != mp.end()) {
        mp.clear();
        Ans ++;
      }
      mp[F] = 1;
    } 
    cout << Ans << '\n';
  }
  return 0;
}
View Code

 

posted @ 2021-08-12 07:28  19992147  阅读(38)  评论(0编辑  收藏  举报