好题选讲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,快两倍多。