好题选讲1

CF1850G *1500

每个点都会对经过它的四个方向的直线产生贡献,于是记录下每个方向每条直线上的点数,然后枚举指南针算贡献即可。

Code
// STOOOOOOOOOOOOOOOOOOOOOOOOO hzt CCCCCCCCCCCCCCCCCCCCCCCORZ
#include <algorithm>
#include <iostream>
#include <map>
#include <numeric>
#include <vector>

using namespace std;
using LL = long long;
using PII = pair<int, int>;
constexpr int kN = 2e5 + 1;
#define x first
#define y second

int T, n, m;
PII p[kN];
map<int, int> m1, m2, m3, m4;
int main() {
  cin.tie(0)->sync_with_stdio(0);
  cin >> T;
  for (; T--;) {
    cin >> n;
    for (int i = 1; i <= n; i++) {
      cin >> p[i].x >> p[i].y;
      m1[p[i].x]++, m2[p[i].y]++;
      m3[p[i].x - p[i].y]++;
      m4[p[i].x + p[i].y]++;
    }
    LL ans = 0;
    for (int i = 1; i <= n; i++) {
      ans += m1[p[i].x] + m2[p[i].y] + m3[p[i].x - p[i].y] + m4[p[i].x + p[i].y] - 4;
    }
    cout << ans << '\n';
    m1.clear(), m2.clear(), m3.clear(), m4.clear();
  }
  return 0;
}

CF306D *2300

发现可以构造一个正 \(n\) 边形,然后对每条边加以不同且很小的边长偏扰,比如逆时针考虑,对第 \(i\) 条边加上 \(i\epsilon\)。但是这样多边形无法闭合,否则角度不同。所以可以特殊考虑最后一个点位置。令第一个点在原点上,多边形始终在 \(x\) 轴之上,最后一条边在 \(x\) 轴上,那么最后一个点就直接按照角度求与 \(x\) 轴交点。

那为什么这个构造方案他不会出现边长相同呢?首先前 \(n-2\) 条边是递增的。把这些边分为左右两边,因为边长递增,所以右边除去第一条边的向上长度短于左边,所以第 \(n-1\) 条边短于第 \(1\) 条边,也短于其他所有边。同理,把这些边分成上下两部分,本来应该是边长相近的,但是第 \(n-1\) 条边遥遥落后于其他边,所以第 \(n\) 条边就要遥遥长于其他边。

代码非常好写。

Code
// STOOOOOOOOOOOOOOOOOOOOOOOOO hzt CCCCCCCCCCCCCCCCCCCCCCCORZ
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <vector>

using namespace std;
using LL = long long;
using PII = pair<int, int>;

int n;
int main() {
  cin.tie(0)->sync_with_stdio(0);
  cin >> n;
  if (n < 5) {
    cout << "No solution\n";
    return 0;
  }
  double agl = 0, c = acos(-1) * 2 / n, len = 500;
  double x = 0, y = 0;
  cout << fixed << setprecision(3);
  for (int i = 1; i < n; i++) {
    cout << x << ' ' << y << '\n';
    agl += c, len += 1e-2;
    i < n - 1 && (x += len * cos(agl), y += len * sin(agl));
  }
  cout << x - y / tan(agl) << ' ' << 0 << '\n';
  return 0;
}

P3480

不少于前一堆的石子个数真的很难直接考虑,很容易想到差分去除这个限制。差分后一次操作就变成了取一个堆中的若干个石子,并把它扔到后一堆去。

翻转序列。这里只有第一堆可以使石子消失,非常特殊。但是似乎第偶数堆就是个废物,从奇数堆移到偶数堆和移除了这些石子等价,因为如果从偶数堆移动到奇数堆,对方也可以把你移动到奇数堆的石子移到偶数堆,直到移动到第零堆,对局面没有影响。

于是变成了只考虑奇数堆的 nim。

Code
// STOOOOOOOOOOOOOOOOOOOOOOOOO hzt CCCCCCCCCCCCCCCCCCCCCCCORZ
#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>

using namespace std;
using LL = long long;
using PII = pair<int, int>;
constexpr int kN = 1e3 + 1;

int T, n, a[kN];
int main() {
  cin.tie(0)->sync_with_stdio(0);
  for (cin >> T; T--;) {
    cin >> n;
    for (int i = 1; i <= n; i++) {
      cin >> a[i];
    }
    int ans = 0;
    for (int i = n; i >= 1; i -= 2) {
      ans ^= a[i] - a[i - 1];
    }
    cout << (ans ? "TAK" : "NIE") << '\n';
  }
  return 0;
}

CF1103B *2000

这种题目第一时间想到怎么得到 \(a\) 与另一个数的大小关系。

发现问 \(?\ \ x\ \ 2x\) 若回答 \(x\) 就有 \(x < a \leq 2x\),否则有 \(2x < a\)
显然可以通过 \(\log n\) 次询问得到一个 \(x\) 使 \(x < a \leq 2x\)
接下来考虑二分。询问 \(?\ \ l\ \ mid\) 后,如果回答 \(x\) 就有 \(l < a \leq mid\);如果回答 \(y\) 就有 \(mid < a \leq r\)

总共 \(2\log n\) 次询问,足以通过此题。

\(\\\)

Code
// stODDDDDDDDDDDDDDDDDDDDDDDDDDD hzt CCCCCCCCCCCCCCCCCCCCCCCCCOrz

#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>

using namespace std;
using LL = long long;
using PII = pair<int, int>;

char c;
string s;
bool Q(int x, int y) {
  cout << "? " << x << ' ' << y << endl;
  cin >> c;
  return c - 'x';
}

int main() {
  for (; cin >> s && s == "start";) {
    int x = 1;
    for (; Q(x / 2, x) && x <= 1e9; x *= 2) {
    }
    int l = x / 2, r = x;
    while (l < r - 1) {
      int m = (l + r) / 2;
      if (!Q(l, m)) {
        r = m;
      } else {
        l = m;
      }
    }
    cout << "! " << r << endl;
  }
  return 0;
}

CF1766D *1600

不难发现\(x, y\)互质 等同于 \(\gcd(x, y)=1\)。但是要考虑到的 \(x\)\(y\) 都是变量,就很烦,于是你发现对于每个询问,需要考虑到的 \(x-y\) 永远不变。

所以利用 gcd 的性质,把 \(\gcd(x+i, y+i)\) 转换为 \(\gcd(x+i, y-x)\),这时 \(y-x\) 就是一个恒定的量。

现在问题就简单很多了。发现不互质时 \(x+i\) 必定是 \(y-x\) 的一个质因子的倍数,所以可以直接枚举 \(y-x\) 的质因子 \(p\),然后随便找 \(x\) 后第一个 \(p\) 的倍数。

但是它直接暴力找质因子复杂度是 \(n\sqrt{V}\) 的,无法通过。但是你发现在这个值域内的一个数的不同质因子个数不超过 \(8\),所以可以暴力存下,质数筛时顺便算出。

Code
// STOOOOOOOOOOOOOOOOOOOOOOOOO hzt CCCCCCCCCCCCCCCCCCCCCCCORZ
#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>

using namespace std;
using LL = long long;
using PII = pair<int, int>;
constexpr int kN = 1e7 + 1;

int T, x, y;
int p[kN][8], c[kN];
bool t[kN];
int main() {
  cin.tie(0)->sync_with_stdio(0);
  for (int i = 2; i < kN; i++) {
    if (!t[i]) {
      for (int j = i; j < kN; j += i) {
        p[j][c[j]++] = i;
        t[j] = 1;
      }
    }
  }
  for (cin >> T; T--;) {
    cin >> x >> y, y -= x;
    if (y == 1) {
      cout << "-1\n";
      continue;
    }
    int ans = 1e9;
    for (int i : p[y]) {
      i != 0 && (ans = min(ans, (i - x % i) % i));
    }
    cout << ans << '\n';
  }
  return 0;
}

Update:爆标了,只需要找 \(\sqrt{V}\) 以内的质数,所以复杂度貌似是 \(n^{\frac{5}{4}}\) 的,直接薄纱 polylog,快两倍多。

posted @ 2024-03-10 11:39  Lightwhite  阅读(43)  评论(0)    收藏  举报