• 「考前日志」11.18


    总结

    有点活过来了

    • 并查集可以用来维护连通块,还可以用来维护自身的特殊信息。
    • 做题要大胆猜结论。
    • 数据随机的题目考虑乱搞。
    • 对于一类 (a_i-a_jle i - j) 的式子,可以移项搞一下转化为 (a_i-ile{a_j-j}) 从而消除某些限制。
    • 负无穷和 (0) 不是一种东西。

    今日已完成

    • 某场模拟赛 网格图

      /*
      知识点:并查集 
      学到了什么:
      并查集可以用来维护连通块,还可以用来维护自身的特殊信息。
      */ 
      const int dx[] = {0, 0, -1, 1};
      const int dy[] = {1, -1, 0, 0};
      char s[A][A];
      int n, m, fa[A * A], ans;
      
      inline int id(int x, int y) {
        return x * (m + 1) + y;
      }
      
      int find(int x) {
        return x == fa[x] ? x : fa[x] = find(fa[x]);
      }
      
      namespace Right {
        //表示每个点右边的第一个0 
        //用并查集可以快速维护 
        int ff[A * A];
        int Find(int x) {
          return x == ff[x] ? x : ff[x] = Find(ff[x]);
        } 
        void Union(int x, int y) {
          int fx = Find(x), fy = Find(y);
          ff[fx] = fy;
        } 
      }
      
      int main() {
        n = read(), m = read();
        for (int i = 1; i <= n; i++) scanf("%s", s[i] + 1);
        int all = (n + 1) * (m + 1);
        for (int i = 1; i <= all; i++) fa[i] = Right::ff[i] = i;
        //首先计算出连通块的个数 
        //再之后更新 
        for (int i = 1; i <= n; i++) {
          for (int j = 1; j <= m; j++) {
            if (s[i][j] != '1') continue; 
            //先标记为一个新的连通块 
            ans++;
            for (int k = 0; k < 4; k++) {
              int bx = i + dx[k], by = j + dy[k];
              if (s[bx][by] != '1') continue;
              int fz1 = find(id(i, j)), fz2 = find(id(bx, by));
              if (fz1 != fz2) {
                //两者相邻但不为同一连通块
                //要标记成同一连通块,所以ans-- 
                ans--;
                if (rand() & 1) swap(fz1, fz2);
                fa[fz1] = fz2;
              }
            }
            Right::Union(id(i, j), id(i, j + 1));
          }
        }
        cout << ans << '
      ';
        int Q = read();
        while (Q--) {
          int X1 = read(), Y1 = read(), X2 = read(), Y2 = read();
          for (int x = X1; x <= X2; x++) {
            //找x,y1右边的第一个0,看是否在y2左边
            //如果在左边就像上面一样更新,否则直接退出。 
            int pos = Right::Find(id(x, Y1));
            int goal = id(x, Y2);
            while (pos <= goal) {
              int y = pos % (m + 1);
              if (!y) y = m + 1;
              ans++;
              for (int k = 0; k < 4; k++) {
                int bx = x + dx[k], by = y + dy[k];
                if (s[bx][by] != '1') continue;
                int fz1 = find(pos), fz2 = find(id(bx, by));
                if (fz1 != fz2) {
                  ans--;
                  if (rand() & 1) swap(fz1, fz2);
                  fa[fz1] = fz2;
                }
              }
              s[x][y] = '1';
              Right::Union(pos, id(x, y + 1));
              pos = Right::Find(id(x, y));
            }
          }
          cout << ans << '
      ';
        }
      }
      
    • 某场模拟赛 && 洛谷 P1439 最长公共子序列

      这考试竟然考板子,真是爱了爱了。

      int n, a[A], b[A], cx[A], f[A], len = 0;
      
      int main() {
        n = read();
        for (int i = 1; i <= n; i++) a[i] = read(), cx[a[i]] = i;
        for (int i = 1; i <= n; i++) b[i] = read();
        f[++len] = cx[b[1]];
        for (int i = 2; i <= n; i++) {
          if (cx[b[i]] >= f[len]) f[++len] = cx[b[i]];
          else {
            int k = lower_bound(f + 1, f + 1 + len, cx[b[i]]) - f;
            f[k] = cx[b[i]];
          }
        }
        cout << len << '
      ';
        return 0;
      }
      
    • A. 【18提高7】模仿游戏

      数据随机,爆搜+剪枝可过

      void dfs(int cnt) {
        if (cnt == m) {
          for (int i = 0; i < m; i++) cout << a[i] << " ";
          puts("");
          for (int i = 0; i < m; i++) cout << b[i] << " ";
          puts("");
          exit(0);
        }
        for (int i = 0; i < m; i++) {
          if (vis[i]) continue;
          a[cnt] = i;
          tot = 0;
          int flag = 0, siz = ys[cnt].size(); 
          for (int j = 0; j < siz; j++) {
            int xj = ys[cnt][j], goal = (a[cnt] + (xj - 1) / m) % m;
            if (b[goal] != y[xj] && b[goal] != -1) { flag = 1; break; }
            if (b[goal] == -1) c[++tot] = goal, b[goal] = y[xj];
          }
          if (flag) {
            for (int j = 1; j <= tot; j++) b[c[j]] = -1;
            continue;
          }
          vis[i] = 1;
          dfs(cnt + 1);
          vis[i] = 0;
          for (int j = 1; j <= tot; j++) b[c[j]] = -1;
        }
      }
      
      int main() {
        n = read(), m = read();
        for (int i = 1; i <= n; i++) x[i] = read();
        for (int i = 1; i <= n; i++) y[i] = read();
        memset(b, -1, sizeof(b));
        for (int i = 1; i <= n; i++) {
          int goal = (x[i] + i - 1) % m;
          ys[goal].push_back(i);
        }
        dfs(0);
        return 0;
      }
      /*
      0 1 6 10 3 4 5 11 9 8 13 2 7 12 
      7 3 0 4 5 11 1 13 10 2 9 6 12 8 
      */
      
    • 洛谷 P4290 [HAOI2008]玩具取名

      区间DP基础题

      char s[A];
      int ok[5][5][5], f[A][A][5], le[A];
      
      int calc(char s) {
        if (s == 'W') return 1;
        else if (s == 'I') return 2;
        else if (s == 'N') return 3;
        else if (s == 'G') return 4;
      }
      
      int main() {
        for (int i = 1; i <= 4; i++) le[i] = read();
        for (int i = 1; i <= 4; i++)
          for (int j = 1; j <= le[i]; j++) {
            scanf("%s", s);
            ok[i][calc(s[0])][calc(s[1])] = 1;
          }
        scanf("%s", s + 1);
        int n = strlen(s + 1);
        for (int i = 1; i <= n; i++) f[i][i][calc(s[i])] = 1;
        for (int len = 1; len <= n; len++) {
          for (int l = 1; l <= n - len + 1; l++) {
            int r = (l + len);
            for (int mi = l; mi < r; mi++) 
              for (int zt1 = 1; zt1 <= 4; zt1++) if (f[l][mi][zt1]) 
                for (int zt2 = 1; zt2 <= 4; zt2++) if (f[mi + 1][r][zt2]) 
                  for (int zt3 = 1; zt3 <= 4; zt3++) if (ok[zt3][zt1][zt2]) f[l][r][zt3] = 1;
          }
        }
        int flag = 0;
        if (f[1][n][1]) flag = 1, cout << "W";
        if (f[1][n][2]) flag = 1, cout << "I";
        if (f[1][n][3]) flag = 1, cout << "N";
        if (f[1][n][4]) flag = 1, cout << "G";
        if (!flag) puts("The name is wrong!");
        return 0;
      }
      
    • CF1433F Zero Remainder Sum

      非常好玩的状态设计

      int n, m, k, a[A][A], f[A][A][A], g[A][A];
      //设f_{j,cnt,r} 表示当前行选了 cnt 个数的和 
      //且 cnt 个数的和 mod k = r
      
      int main() {
        n = read(), m = read(), k = read();
        for (int i = 1; i <= n; i++) 
          for (int j = 1; j <= m; j++) a[i][j] = read();
        memset(g, 0xcf, sizeof(g));
        g[0][0] = 0;
        for (int i = 1; i <= n; i++) {
          memset(f, 0xcf, sizeof(f));
          //debug:把初始化放在了j里 
          for (int j = 0; j <= m; j++) f[j][0][0] = 0;
          for (int j = 1; j <= m; j++) {
            for (int cnt = 1; cnt <= m / 2; cnt++)
              for (int r = 0; r < k; r++)  
                f[j][cnt][r] = max(f[j - 1][cnt][r], f[j - 1][cnt - 1][((r - a[i][j]) % k + k) % k] + a[i][j]);
          }
          for (int j = 0; j < k; j++) {
            for (int cnt = 0; cnt <= m / 2; cnt++)
              for (int r = 0; r < k; r++)
                g[i][j] = max(g[i][j], g[i - 1][((j - f[m][cnt][r]) % k + k) % k] + f[m][cnt][r]);
          }
        }
        cout << max(0, g[n][0]) << '
      ';
        return 0;
      }
      
  • 相关阅读:
    并查集
    CCF201604-02
    作业八
    作业七
    数据结构--链队列基本操作
    数据结构--栈的基本操作
    eclipse配置maven
    软件架构
    scala lambda 表达式 & spark RDD函数操作
    spark(3)
  • 原文地址:https://www.cnblogs.com/loceaner/p/14003233.html
Copyright © 2020-2023  润新知