zoukankan      html  css  js  c++  java
  • 【做题】agc016d

    原文链接 https://www.cnblogs.com/cly-none/p/9813163.html

    题意:给出初始序列(a)和目标序列(b),都有(n)个元素。每次操作可以把(a)中的一个元素替换为(a)中所有元素的异或和,问最少操作多少次,把序列(a)变成序列(b),或判断无解。

    (n leq 10^5)

    首先,这个“替换为所有元素的异或和”,其实就是一开始有(v)(a)中所有元素异或和,每次操作把(a)中某个元素与(v)交换。再转化一下,也就是一开始(a_0)(a)中所有元素的异或和,每次可以把(a)中的某个元素和(a_0)交换。

    这样很容易能判断无解的情况。现在只考虑如何求出操作的最小次数。

    先不考虑元素相等的情况。那么就变成了一个排列的置换。考虑其中的每一个环,设环大小为(m \, (m > 1)),假如其中不包含(a_0),那么这个环就需要(m+1)次操作来处理;否则只需要(m-1)次。

    而当有元素相等时,我们也可以类似于排列处理。定义每一对((a_i,b_i))产生一条((a_i,b_i))的有向边。因为包含(a_0)的环的个数是固定的,所以要最小化答案,我们就要最小化环的个数。但是这道题的图存在特殊性质:每一个弱连通分量都是由若干个有向环组成的,这意味着一定存在欧拉闭迹。因此,每个连通分量都能用只一个环解决。这显然也是答案的下界。

    然后还有(a_0)的一点细节。

    • (a_0 eq b_0)。那么,(a_0)一定在一个大于1的环上。最终答案减二。
    • (a_0 = b_0),但(a_0)所在的弱连通分量大于1。这样,那个弱连通分量的操作个数能少一个。
    • (a_0 = b_0),且(a_0)所在弱连通分量大小为1。那它对答案没有什么影响。

    时间复杂度(O(n log n))

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 100010;
    int a[N],n,b[N],tmp,ans,cur,uni[N],sz[N],vis[N];
    map<int,int> mp;
    typedef pair<int,int> pii;
    vector<int> vec;
    template <typename tp>
    void outputarr(tp *a,tp *b) {
      while (a != b)
        cerr << *a << ' ', ++ a;
      cerr << endl;
    }
    int getfa(int pos) {
      return pos == uni[pos] ? pos : uni[pos] = getfa(uni[pos]);
    }
    int main() {
      scanf("%d",&n);
      for (int i = 1 ; i <= n ; ++ i)
        scanf("%d",&a[i]), tmp ^= a[i];
      a[0] = tmp;
      for (int i = 1 ; i <= n ; ++ i)
        scanf("%d",&b[i]);
      for (int i = 0 ; i <= n ; ++ i)
        ++ mp[a[i]];
      for (int i = 1 ; i <= n ; ++ i) {
        if (!mp.count(b[i]))
          return puts("-1"), 0;
        if (mp[b[i]] == 0) return puts("-1"), 0;
        mp[b[i]]--;
      }
      for (int i = 0 ; i <= n ; ++ i)
        if (mp[a[i]]) b[0] = a[i];
      for (int i = 0 ; i <= n ; ++ i)
        vec.push_back(a[i]);
      sort(vec.begin(),vec.end());
      vec.erase(unique(vec.begin(),vec.end()),vec.end());
      for (int i = 0 ; i <= n ; ++ i)
        a[i] = lower_bound(vec.begin(),vec.end(),a[i]) - vec.begin() + 1, 
          b[i] = lower_bound(vec.begin(),vec.end(),b[i]) - vec.begin() + 1;
      for (int i = 0 ; i <= n ; ++ i)
        uni[a[i]] = a[i];
      for (int i = 0 ; i <= n ; ++ i) {
        int x = getfa(a[i]), y = getfa(b[i]);
        if (x != y)
          uni[x] = y;
      }
      for (int i = 0 ; i <= n ; ++ i) {
        if (a[i] == b[i]) continue;
        ++ ans;
        ++ sz[getfa(a[i])];
      }
      for (int i = 0 ; i <= n ; ++ i) {
        if (a[i] == b[i]) continue;
        if (a[i] == getfa(a[i]) && !vis[a[i]]) {
          ++ ans;
          vis[a[i]] = 1;
        }
      }
      if (a[0] != b[0]) ans --;
      if (sz[getfa(a[0])] > 1) ans --;
      printf("%d
    ",ans);
      return 0;
    }
    

    小结:早上的训练赛搬了这道题。从我的FST中,也可以看出我对问题的考虑不够仔细。补题过程中思维混乱的问题也很明显,导致花费了很多时间。

  • 相关阅读:
    web前端的发展态势
    AngularJs 简单入门
    css代码优化篇
    git提交报错:Please make sure you have the correct access rights and the repository exists.
    Activiti工作流框架学习
    遍历map集合的4种方法
    js设置日期、月份增加减少
    Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
    webservice_rest接口_学习笔记
    相互匹配两个list集合+动态匹配${}参数
  • 原文地址:https://www.cnblogs.com/cly-none/p/9813163.html
Copyright © 2011-2022 走看看