zoukankan      html  css  js  c++  java
  • LOJ2323. 「清华集训 2017」小 Y 和地铁 【搜索】【思维】【好】

    LINK


    思路

    首先如果直接算每一个段有三个决策
    左/右 上/下 跨不跨过端点
    这样的复杂度是((2^3)^{22}),显然是无法接受的
    然后考虑怎么优化这个东西
    首先左右这个决策是没有意义的
    因为无论是左还是右,对答案的相对影响是不变的
    其次考虑用a和b分别表示上下和跨不跨过端点的决策
    然后退一下就可发现有很多种情况是可以归约的
    大概成了这样

    void dfs(int tmp, int res) {
      if (res >= ans) return;
      if (tmp > n) {
        ans = res;
        return;
      }
      if (cnt[t[tmp]] == 1 || pre[tmp]) {
        dfs(tmp + 1, res);
        return;
      }
      int now;
      a[tmp] = 0;
      b[tmp] = 0;
      now = res;
      fu(i, 1, tmp - 1) 
        if (!(a[i] ^ b[i]) && nxt[i] > tmp && nxt[i] < nxt[tmp]) ++now;
      dfs(tmp + 1, now);
      a[tmp] = 0;
      b[tmp] = 1;
      now = res;
      fu(i, 1, tmp - 1) {
        if ((a[i] ^ b[i]) && nxt[i] > nxt[tmp]) ++now;
        if (!(a[i] ^ b[i]) && nxt[i] > tmp) ++now;
      }
      dfs(tmp + 1, now);
      a[tmp] = 1;
      b[tmp] = 0;
      now = res;
      fu(i, 1, tmp - 1) 
        if ((a[i] ^ b[i]) && nxt[i] > tmp && nxt[i] < nxt[tmp]) ++now;
      dfs(tmp + 1, now);
      a[tmp] = 1;
      b[tmp] = 1;
      now = res;
      fu(i, 1, tmp - 1) {
        if (!(a[i] ^ b[i]) && nxt[i] > nxt[tmp]) ++now;
        if ((a[i] ^ b[i]) && nxt[i] > tmp) ++now;
      }
      dfs(tmp + 1, now);
    }
    

    这样是可以得到64分的高分的
    但是并不够
    继续考虑怎么压缩状态
    发现前面的每个已经决策的区间对当前区间的影响只有a和b的异或和
    所以每次只枚举a和b的异或和
    但是a和b的异或和相等的情况有两种
    但是这两种对后面决策的影响都是相同的
    所以直接贪心取最小的就可以了
    复杂度(n*2^{n/2})


    AC代码


    //Author: dream_maker
    #include<bits/stdc++.h>
    using namespace std;
    //----------------------------------------------
    //typename
    typedef long long ll;
    //convenient for
    #define fu(a, b, c) for (int a = b; a <= c; ++a)
    #define fd(a, b, c) for (int a = b; a >= c; --a)
    #define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
    //inf of different typename
    const int INF_of_int = 1e9;
    const ll INF_of_ll = 1e18;
    //fast read and write
    template <typename T>
    void Read(T &x) {
      bool w = 1;x = 0;
      char c = getchar();
      while (!isdigit(c) && c != '-') c = getchar();
      if (c == '-') w = 0, c = getchar();
      while (isdigit(c)) {
        x = (x<<1) + (x<<3) + c -'0';
        c = getchar();
      }
      if (!w) x = -x;
    }
    template <typename T>
    void Write(T x) {
      if (x < 0) {
        putchar('-');
        x = -x; 
      }
      if (x > 9) Write(x / 10);
      putchar(x % 10 + '0');
    }
    //----------------------------------------------
    const int N = 50;
    int t[N], n, ans;
    int pre[N], nxt[N], last[N], cnt[N];
    bool a[N], b[N], mark[N];
    //a 走上面(0)还是下面(1)
    //b 不跨过(0)还是跨过(1)
    int T;
    /*void dfs(int tmp, int res) {
      if (res >= ans) return;
      if (tmp > n) {
        ans = res;
        return;
      }
      if (cnt[t[tmp]] == 1 || pre[tmp]) {
        dfs(tmp + 1, res);
        return;
      }
      int now;
      a[tmp] = 0;
      b[tmp] = 0;
      now = res;
      fu(i, 1, tmp - 1) 
        if (!(a[i] ^ b[i]) && nxt[i] > tmp && nxt[i] < nxt[tmp]) ++now;
      dfs(tmp + 1, now);
      a[tmp] = 0;
      b[tmp] = 1;
      now = res;
      fu(i, 1, tmp - 1) {
        if ((a[i] ^ b[i]) && nxt[i] > nxt[tmp]) ++now;
        if (!(a[i] ^ b[i]) && nxt[i] > tmp) ++now;
      }
      dfs(tmp + 1, now);
      a[tmp] = 1;
      b[tmp] = 0;
      now = res;
      fu(i, 1, tmp - 1) 
        if ((a[i] ^ b[i]) && nxt[i] > tmp && nxt[i] < nxt[tmp]) ++now;
      dfs(tmp + 1, now);
      a[tmp] = 1;
      b[tmp] = 1;
      now = res;
      fu(i, 1, tmp - 1) {
        if (!(a[i] ^ b[i]) && nxt[i] > nxt[tmp]) ++now;
        if ((a[i] ^ b[i]) && nxt[i] > tmp) ++now;
      }
      dfs(tmp + 1, now);
    }*/
    void dfs(int tmp, int res) {
      if (res >= ans) return;
      if (tmp > n) {
        ans = res;
        return;
      }
      if (cnt[t[tmp]] == 1 || pre[tmp]) {
        dfs(tmp + 1, res);
        return;
      }
      int now1, now2;
      mark[tmp] = 0;
      now1 = now2 = res;
      fu(i, 1, tmp - 1) { 
        if (!mark[i] && nxt[i] > tmp && nxt[i] < nxt[tmp]) ++now1;
        if (!mark[i] && nxt[i] > nxt[tmp]) ++now2;
        if (mark[i] && nxt[i] > tmp) ++now2;
      }
      dfs(tmp + 1, min(now1, now2));
      mark[tmp] = 1;
      now1 = now2 = res;
      fu(i, 1, tmp - 1) {
        if (mark[i] && nxt[i] > tmp && nxt[i] < nxt[tmp]) ++now1;
        if (mark[i] && nxt[i] > nxt[tmp]) ++now2;
        if (!mark[i] && nxt[i] > tmp) ++now2;
      }
      dfs(tmp + 1, min(now1, now2));
    }
    void solve() {
      Read(n);
      fu(i, 1, n) pre[i] = nxt[i] = last[i] = cnt[i] = 0;
      fu(i, 1, n) {
        Read(t[i]);
        ++cnt[t[i]];
        if (last[t[i]]) {
          pre[i] = last[t[i]];
          nxt[last[t[i]]] = i;
        } else {
          last[t[i]] = i;
        }
      }
      ans = INF_of_int;
      dfs(1, 0);
      printf("%d
    ", ans);
    }
    int main() {
      freopen("input.txt","r",stdin);
      Read(T);
      while (T--) solve();
      return 0;
    }
    
  • 相关阅读:
    java作用域public ,private ,protected 及不写时的区别
    JAVA的静态变量、静态方法、静态类
    栈内存 堆内存
    java
    数组 bash shell
    SYN Cookie的原理和实现
    Python 时间 time
    sysctl命令详解
    lvs
    软件工程概论个人作业01
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9735656.html
Copyright © 2011-2022 走看看