zoukankan      html  css  js  c++  java
  • CF-595

    题目传送门

    A .Yet Another Dividing into Teams

    sol:原先是用比较复杂的方法来解的,后来学弟看了一眼,发现不是1就是2,当出现两个人水平相差为1就分成两组,1组全是奇数,1组全是偶数,必然符合题意。

    • 思维
      #include "bits/stdc++.h"
      using namespace std;
      #define debug puts("what the fuck");
      typedef long long LL;
      typedef pair<int, int> PII;
      const int MAXN = 110;
      bool vis[MAXN];
      int main() {
          int t, n, m;
          scanf("%d", &t);
          while (t--) {
              scanf("%d", &n);
              bool ok = true;
              memset(vis, false, sizeof(vis));
              for (int i = 1; i <= n; i++) {
                  scanf("%d", &m);
                  vis[m] = true;
                  if (vis[m - 1] || vis[m + 1]) ok = false;
              }
              if (ok) puts("1");
              else puts("2");
          }
          return 0;
      }
      View Code

    B. Books Exchange

    sol:很裸的并查集,i和p[i]属于同一个集合,求每个点所在集合的大小

    • 并查集
      #include "bits/stdc++.h"
      using namespace std;
      #define debug puts("what the fuck");
      typedef long long LL;
      typedef pair<int, int> PII;
      const int MAXN = 2e5 + 10;
      int pre[MAXN], cnt[MAXN];
      int find(int i) {
          if (pre[i] == i) return i;
          return pre[i] = find(pre[i]);
      }
      int main() {
          int t, n, m;
          scanf("%d", &t);
          while (t--) {
              scanf("%d", &n);
              for (int i = 1; i <= n; i++) {
                  cnt[i] = 1;
                  pre[i] = i;
              }
              for (int i = 1; i <= n; i++) {
                  scanf("%d", &m);
                  int u = find(i);
                  int v = find(m);
                  if (u != v) {
                      pre[u] = v;
                      cnt[v] += cnt[u];
                  }
              }
              for (int i = 1; i <= n; i++)
                  printf("%d ", cnt[find(i)]);
              puts("");
          }
          return 0;
      }
      View Code

    C1. Good Numbers (easy version)

    sol:由于n比较小,所以我们可以暴力罗列good number,pow(3, 10)已经大于n的最大范围10000,所以罗列到3的10次方够了,再组合一下,排序后用二分去搜就好了。

    • 暴力组合
      #include "bits/stdc++.h"
      using namespace std;
      #define debug puts("what the fuck");
      typedef long long LL;
      typedef pair<int, int> PII;
      int p[20] = {1};
      vector<int> v;
      void init() {
          for (int i = 1; i <= 10; i++)
              p[i] = 3 * p[i - 1];
          for (int i = 1; i <= (1 << 10); i++) {
              int sum = 0;
              for (int j = 0; j <= 10; j++)
                  if (i & (1 << j)) sum += p[j];
              v.push_back(sum);
          }
      }
      int main() {
          int t, n;
          scanf("%d", &t);
          init();
          sort(v.begin(), v.end());
          while (t--) {
              scanf("%d", &n);
              printf("%d
      ", *lower_bound(v.begin(), v.end(), n));
          }
          return 0;
      }
      View Code

    C2. Good Numbers (hard version)

    sol:细看这题感觉和进制有关,把n转成3进制后找到第一个大于等于n并且所以三进制位不为2的数;

    • 进制
      #include "bits/stdc++.h"
      using namespace std;
      #define debug puts("what the fuck");
      typedef long long LL;
      typedef pair<int, int> PII;
      int p[60];
      int main() {
          int t;
          LL n, pos;
          scanf("%d", &t);
          while (t--) {
              scanf("%lld", &n);
              memset(p, 0, sizeof(p));
              pos = 0;
              while (n) {
                  p[pos++] = n % 3;
                  n /= 3;
              }
              int k = pos - 1;
              while (k > 0 && p[k] != 2) k--; // 从高位往低位搜找到第一个2
              for (int i = k - 1; i >= 0; i--) p[i] = 0; // 第k位加1,那么k之前的位可以全部为0了,一定不会小于n
              while (p[k] == 2) { //进位
                  p[k] = 0;
                  p[++k] ++;
              }
              pos = max(pos, k + 1LL);
              LL sum = 0, pp = 1;
              for (int i = 0; i < pos; i++) {
                  if (p[i] == 1) sum += pp;
                  pp *= 3;
              }
              printf("%lld
      ", sum);
          }
          return 0;
      }
      View Code

    D. Too Many Segments 

    sol:用差分确定覆盖每个点的线段有多少条,对于点i,如果覆盖的线段数量大于k,删掉覆盖该点的右端点最远的线段,可以用优先队列找这样的线段。就是需要两个排序方式。

    • 贪心,差分
      #include "bits/stdc++.h"
      using namespace std;
      #define debug puts("what the fuck");
      typedef long long LL;
      typedef pair<int, int> PII;
      const int MAXN = 2e5 + 10;
      struct Seg {
          int l, r;
          int index;
          friend bool operator < (Seg a, Seg b) {return a.r < b.r;}
      } a[MAXN];
      priority_queue<Seg> que;
      bool cmp(Seg a, Seg b) {return a.l < b.l;}
      vector<int> ans;
      int cnt[MAXN], pos, sum;
      int main() {
          int n, m;
          scanf("%d%d", &n, &m);
          for (int i = 1; i <= n; i++) {
              scanf("%d%d", &a[i].l, &a[i].r);
              a[i].index = i;
          }
          sort(a + 1, a + 1 + n, cmp);
          for (int i = 1; i <= n; i++) {
              while (pos < a[i].l) sum += cnt[++pos];
              que.push(a[i]);
              sum ++, cnt[a[i].r + 1] --;
              if (sum > m) {
                  sum --;
                  Seg s = que.top();
                  que.pop();
                  cnt[s.r + 1] ++;
                  ans.push_back(s.index);
              }
          }
          printf("%d
      ", ans.size());
          for (auto index : ans) printf("%d ", index);
          return 0;
      }
      View Code

    E. By Elevator or Stairs?

    sol:dp,dp[0][i]表示从a[i]到1的最少时间,dp[1][i]表示从b[i]到1的最少时间。代码中直接把a、b数组当dp[0]和dp[1]来用了;

    • 动态规划
      #include "bits/stdc++.h"
      using namespace std;
      #define debug puts("what the fuck");
      typedef long long LL;
      typedef pair<int, int> PII;
      const int MAXN = 2e5 + 10;
      int a[MAXN], b[MAXN];
      int main() {
          int n, c;
          scanf("%d%d", &n, &c);
          a[1] = 0, b[1] = c;
          for (int i = 2; i <= n; i++) scanf("%d", &a[i]);
          for (int i = 2; i <= n; i++) scanf("%d", &b[i]);
          for (int i = 1; i <= n; i++) {
              a[i] += min(a[i - 1], b[i - 1]);
              b[i] += min(a[i - 1] + c, b[i - 1]);
              printf("%d ", min(a[i], b[i]));
          }
          return 0;
      }
      View Code

    F. Maximum Weight Subset

    sol:树形dp,dp[u][dep]表示u子树中距离u最近的选取点离u的距离不小于dep的最大权重。要注意的是合并的时候两颗子树间的选取点距离也不能小于等于k;

    • 树形dp
      #include "bits/stdc++.h"
      using namespace std;
      #define debug puts("what the fuck");
      typedef long long LL;
      typedef pair<int, int> PII;
      const int MAXN = 210;
      int w[MAXN];
      int dp[MAXN][MAXN];
      vector<int> edge[MAXN];
      int n, k;
      void dfs(int u, int fa) {
          for (auto v : edge[u]) {
              if (v == fa) continue;
              dfs(v, u);
          }
          dp[u][0] = w[u];
          for (auto v : edge[u]) {
              if (v == fa) continue;
              dp[u][0] += dp[v][k];
          }
          for (int dep = 1; dep <= k; dep++) {
              for (auto v : edge[u]) {
                  if (v == fa) continue;
                  int sum = dp[v][dep - 1];
                  for (auto other : edge[u]) {
                      if (other == fa || other == v) continue;
                      sum += dp[other][max(dep - 1, k - dep)];
                  }
                  dp[u][dep] = max(dp[u][dep], sum);
              }
          }
          for (int i = k - 1; i >= 0; i--) dp[u][i] = max(dp[u][i], dp[u][i + 1]);
      }
      int main() {
          scanf("%d%d", &n, &k);
          for (int i = 1; i <= n; i++) scanf("%d", &w[i]);
          for (int i = 2; i <= n; i++) {
              int u, v;
              scanf("%d%d", &u, &v);
              edge[u].push_back(v);
              edge[v].push_back(u);
          }
          dfs(1, -1);
          printf("%d
      ", dp[1][0]);
          return 0;
      }
      View Code

      官方题解里vector太多了,看的好懵逼。提交最后解释了一下为什么复杂度是O(n^3)不是O(n^4),但是我看着还是感觉复杂度是O(n^4)

    ——————————————————————————————————————————————————————————————

    第一次把一场CF所有题都补出来,开心

  • 相关阅读:
    Adobe Acrobat XI Pro破解版 v11.0.10中文版
    linux经典面试题
    P1540 机器翻译(STL 链表)
    P1067 多项式输出 (模拟)
    P1003 铺地毯
    [CF547C] Mike and Foam
    [CF351B] Jeff and Furik
    [CF900D] Unusual Sequences
    [CF568B] Symmetric and Transitive
    [CF893E] Counting Arrays
  • 原文地址:https://www.cnblogs.com/Angel-Demon/p/11732290.html
Copyright © 2011-2022 走看看