zoukankan      html  css  js  c++  java
  • Codeforces 1383C String Transformation 2

    题目传送门

      传送门

      我怎么菜到这种比赛也能下分。

      感觉除了 C,这场比赛剩下的题目都有点愚蠢,就懒得写题解了。注意 D 是要求的是集合相同不是数组相同。

      考虑如果 $s_i eq t_i$ 那么在 $G$ 中连一条 $s_i ightarrow t_i$ 的有向边。题目相当于要求在另一个初始没有边的新图 $G'$ 中添加若干边,满足每个点经过时间递增的边能够到达旧图中与它直接相连的点。

      显然每个弱连通块独立。所以假设 $G'$ 弱连通,设图 $G'$ 的点数为 $n$,其中最大的点导出 DAG 的大小为 $m$,那么答案为 $2n - 1 - m$。

      先证明这个是上界,假设不在 DAG 中为 $m + 1, cdots, n$,那么依次操作 $(m + 1, m + 2), (m + 2, m + 3), cdots, (n - 1, n), (n, m + 1), cdots, (m + 1, m  + 2), cdots, (n - 2,n - 1)$,显然此时每个点经过时间递增的边能够到达这中间的所有点,假设 DAG 的拓扑序为 $1, cdots, m$,那么依次操作 $(n - 1, 1), (1, 2), cdots, (m - 1 ,m)$。

      然后证明这是下界,考虑依次进行每个操作,考虑每个弱连通块维护它的最大点导出 DAG。显然这个 DAG 中的点在图 $G$ 中也是一个点导出 DAG。考虑如果操作了 $(u, v)$

    • 如果 $u, v$ 在同一弱连通块内,考虑如果 $v$ 在 DAG 中,那么删掉 $v$,因此点导出的 DAG 之和至多减少 1。
    • 如果在不同弱连通块,那么连接它们的 DAG。

      假设操作了 $k$ 次,那么第二种情况会恰好发生 $n - 1$ 次,情况一至多发生 $k - n + 1$ 次,所以有 $|DAG| geqslant 2n - k - 1$,即 $k geqslant 2n - |DAG| - 1$。当 $|DAG|$ 取到最大值时,即为 $k$ 的下界。

      剩下是一个普及组 dp,相信大家都会。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    typedef bool boolean;
    
    template <typename T>
    boolean vmin(T& a, T b) {
      return (a > b) ? (a = b, true) : (false);
    }
    template <typename T>
    boolean vmax(T& a, T b) {
      return (a < b) ? (a = b, true) : (false);
    }
    
    template <typename T>
    T smax(T x) {
      return x;
    }
    template <typename T, typename ...K>
    T smax(T a, const K &...args) {
      return max(a, smax(args...));
    }
    
    template <typename T>
    T smin(T x) {
      return x;
    }
    template <typename T, typename ...K>
    T smin(T a, const K &...args) {
      return min(a, smin(args...));
    }
    
    // debugging lib
    
    #define VN(x) #x
    #define Vmsg(x) VN(x) << " = " << (x)
    #define printv(x) cerr << VN(x) << " = " << (x);
    #define debug(...) fprintf(stderr, __VA_ARGS__);
    
    template <typename A, typename B>
    ostream& operator << (ostream& os, const pair<A, B>& z) {
      os << "(" << z.first << ", " << z.second << ')';
      return os;
    }
    template <typename T>
    ostream& operator << (ostream& os, const vector<T>& a) {
      boolean isfirst = true;
      os << "{";
      for (auto z : a) {
        if (!isfirst) {
          os << ", ";
        }
        os << z;
        isfirst = false;
      }
      os << '}';
      return os;
    }
    
    #define pii pair<int, int>
    #define pil pair<int, ll>
    #define pli pair<ll, int>
    #define ll long long
    #define ull unsigned long long
    
    const int inf = (signed) (~0u >> 2);
    const ll llf = (signed ll) (~0ull >> 2);
    
    #define pb push_back
    #define eb emplace_back
    #define fi first
    #define sc second
    
    template <typename T>
    int vsize(vector<T>& x) {
      return (signed) x.size(); 
    }
    
    template <typename T>
    int discrete(T* a, int* b, int n) {
      vector<T> v(a + 1, a + n + 1);
      sort(v.begin(), v.end());
      v.erase(unique(v.begin(), v.end()), v.end());
      for (int i = 1; i <= n; i++) b[i] = lower_bound(v.begin(), v.end(), a[i]) - v.begin() + 1;
      return v.size();
    }
    
    mt19937 rng (time(NULL));
    
    int randint(int l, int r) {
      return rng() % (r - l + 1) + l;
    }
    
    const int N = 1e5 + 5;
    
    int T, n;
    char s[N], t[N];
    int G0[22], G[22];
    int uf[22];
    
    int find(int x) {
      return uf[x] == x ? x : (uf[x] = find(uf[x]));
    }
    void unit(int x, int y) {
      x = find(x);
      y = find(y);
      if (x ^ y) {
        uf[x] = y;
      }
    }
    
    int solve(vector<int> p) {
      memset(G, 0, sizeof(G));
      int n = p.size();
      for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
          if ((G0[p[i]] >> p[j]) & 1) {
            G[i] |= (1 << j);
          }
        }
      }
      vector<bool> dp (1 << n, 0);
      dp[0] = true;
      int res = 0;
      for (int s = 0; s < (1 << n); s++) {
        if (!dp[s]) continue;
        res = max(res, __builtin_popcount(s));
        for (int i = 0; i < n; i++) {
          if (!((s >> i) & 1) && !(G[i] & s)) {
            dp[s | (1 << i)] = true;
          }
        }
      }
      return 2 * n - 1 - res;
    }
    
    void solve() {
      cin >> n;
      string s, t;
      cin >> s;
      cin >> t;
      memset(G0, 0, sizeof(G0));
      for (int i = 0; i < 20; i++) {
        uf[i] = i;
      }
      for (int i = 0; i < n; i++) {
        if (s[i] != t[i]) {
          G0[s[i] - 'a'] |= 1 << (t[i] - 'a');
          unit(s[i] - 'a', t[i] - 'a');
        }
      }
      int ans = 0;
      for (int i = 0; i < 20; i++) {
        if (find(i) == i) {
          vector<int> p;
          for (int j = 0; j < 20; j++) {
            if (find(j) == i) {
              p.push_back(j);
            } 
          }
          ans += solve(p);
        }      
      }
      cout << ans << '
    ';
    }
    
    int main() {
      ios::sync_with_stdio(false);
      cin.tie(0), cout.tie(0);
      cin >> T;
      while (T--) {
        solve();
      }
      return 0;
    }
    

      

  • 相关阅读:
    埃拉托色尼的素数查找法的优化问题
    Salesforce开发者学习笔记之三:Salesforce平台架构
    Salesforce开发者学习笔记之二:Salesforce开发平台应用场景
    Salesforce开发者学习笔记之一:基本知识
    Salesforce Apex 使用JSON数据的示例程序
    Salesforce Apex页面中调用远端网络服务
    Salesforce Apex 开发环境设置和Hello World示例
    四、Java 安装
    三、Windows 基础
    二、大数据生态圈尝鲜
  • 原文地址:https://www.cnblogs.com/yyf0309/p/13399928.html
Copyright © 2011-2022 走看看