ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

luogu7843. 「PMOI-4」猜排列(乱搞)

2021-08-21 11:02:16  阅读:176  来源: 互联网

标签:PMOI int bmod 位置 乱搞 vector 27719 询问 luogu7843


题目链接

https://www.luogu.com.cn/problem/P7843

题解

这里给出一种所有子任务下询问问题 2 的次数都不超过 \(13\) 的做法。

朴素的做法是:假设我们想要知道 \([1, m]\) 内的数分别在什么位置,我们可以先询问一次问题 2 来知晓 \((\frac{m}{2}, m]\) 的位置集合,再借助问题 1 用数 \(m + 1\) 去对这些位置上的数分别取模,从而确定出它们各自的值是多少(\(m + 1\) 对 \((\frac{m}{2}, m]\) 内的任意数取模的结果都是不一样的),最后再通过递归来进一步求 \([1, \frac{m}{2}]\) 内的数的位置。这样,我们只需要在最开始先询问一次问题 2 来确定出 \(n\) 的位置,然后利用上述做法求 \([1, n - 1]\) 内的数的位置即可得到整个排列。该方法所需的问题 2 的询问次数为 \(1 + \log n\),当 \(n = 5 \times 10^4\) 时为 \(16\)。

考虑如何优化一次询问。注意到 \(5 \bmod 1 = 0, 5 \bmod 2 = 1, 5 \bmod 3 = 2\),而 \(49999\) 不断(整)除以 \(2\) 恰好会得到 \(6\),也即:当我们想要知道 \([1, 6]\) 内的数分别在什么位置时,我们先确定出 \(4, 5, 6\) 的位置,之后无需再继续递归,而是用 \(5\) 分别对剩下三个未确定位置上的数取模,利用模数就能将 \(1, 2, 3\) 的位置判断出来。这样就节省了一次询问,即在最后一个子任务下只需 \(15\) 次询问 2 即可求出排列。这足以通过本题。

延续上面的思路:如果一个数 \(x\) 除以从 \(1\) 开始的一段连续自然数 \(1 \sim r\) 的余数均不相同,那么利用 \(x\) 就能够把 \(1 \sim r\) 的位置判断出来。又因为 \(x \bmod 1 = 0\),因此 \(x \bmod 2\) 必然为 \(1\),\(x \bmod 3\) 必然为 \(2\)……即 \(x \bmod i = i - 1(1 \leq i \leq r)\)。写一份程序可以找到在 \(50000\) 以内满足这一性质的最佳数 \(x = 27719\),它对应的 \(r = 12\)。也即:如果我们找到了 \(27719\) 的位置,那么当我们递归到 \([1, m]\) 满足 \(m \leq 12\) 时就可以停止使用朴素做法,直接利用 \(27719\) 询问问题 1 就可以确定出 \(1 \sim m\) 所有数的位置。这样当 \(n = 5 \times 10^4\) 时我们在朴素做法的基础上减少了三次递归,问题 2 的询问次数也降至了 \(\log n - 2 = 13\)。

利用 \(27719\) 这一特殊数,子任务 3 和 4 询问问题 2 的次数仍不能得到有效优化,因为这两个子任务的 \(n\) 达不到 \(27719\)。略微缩小查找范围,我们可以找到另一个特殊数 \(2519\),它对应的 \(r = 10\)。使用该数可以使子任务 3 的询问问题 2 的次数降至 \(12\),子任务 4 的询问次数降至 \(11\)。

代码

#include<bits/stdc++.h>

using namespace std;

const int N = 56789;

int n, m1, m2, m3, p2519, p27719, a[N];
bool tag[N];

vector<int> query(vector<int> s, int p) {
  int l = s.size();
  cout << "? " << l;
  for (auto x : s) {
    cout << ' ' << x;
  }
  cout << ' ' << p << '\n';
  cout.flush();
  int n;
  cin >> n;
  vector<int> result(n);
  for (int i = 0; i < n; ++i) {
    cin >> result[i];
  }
  return result;
}

int query(int x, int y) {
  cout << "! " << x << ' ' << y << '\n';
  cout.flush();
  int z;
  cin >> z;
  return z;
}

void solve(int m, int p) {
  vector<int> s;
  for (int i = 1; i <= n; ++i) {
    if (!tag[i]) {
      s.push_back(i);
    }
  }
  if (m == 1) {
    a[s[0]] = 1;
    return;
  }
  if (m <= 12 && p27719) {
    for (auto i : s) {
      a[i] = query(p27719, i) + 1;
    }
    return;
  }
  if (m <= 10 && p2519) {
    for (auto i : s) {
      a[i] = query(p2519, i) + 1;
    }
    return;
  }
  vector<int> x = query(s, (m >> 1) + 1);
  for (auto i : x) {
    tag[i] = true;
    int diff = query(p, i);
    a[i] = diff ? a[p] - diff : (a[p] >> 1);
  }
  for (auto i : x) {
    if (a[i] == (m >> 1) + 1) {
      p = i;
    }
    if (a[i] == 27719) {
      p27719 = i;
    }
    if (a[i] == 2519) {
      p2519 = i;
    }
  }
  solve(m >> 1, p);
}

int main() {
  ios::sync_with_stdio(false);
  cin >> n >> m1 >> m2 >> m3;
  if (n == 4) {
    vector<int> foo = query(vector<int>{1, 2, 3, 4}, 3);
    int x = foo[0], y = foo[1];
    for (int i = 1; i <= 4; ++i) {
      if (i != x && i != y) {
        int z = query(x, i), w = query(y, i);
        if (z == 0 && w == 0) {
          a[i] = 1;
        } else {
          a[i] = 2;
          if (z == 0) {
            a[x] = 4;
            a[y] = 3;
          } else {
            a[x] = 3;
            a[y] = 4;
          }
        }
      }
    }
  } else {
    vector<int> s;
    for (int i = 1; i <= n; ++i) {
      s.push_back(i);
    }
    int p = query(s, n)[0];
    a[p] = n;
    tag[p] = true;
    solve(n - 1, p);
  }
  cout << 'A';
  for (int i = 1; i <= n; ++i) {
    cout << ' ' << a[i];
  }
  cout << '\n';
  cout.flush();
  return 0;
}

标签:PMOI,int,bmod,位置,乱搞,vector,27719,询问,luogu7843
来源: https://www.cnblogs.com/ImagineC/p/15169003.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有