做起来很舒适的一套题。
A – route
假设一个局面:所有可用的点都已经在一侧,那么我们向那一侧走的时候,根据下一次的走向来决定走近似直线还是 Z 字形(也就是取极角序最大或最小)。
// route.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 5055;
typedef long long ll;
int n;
char str[MAX_N];
struct point
{
int x, y;
point(const int x_ = 0, const int y_ = 0) : x(x_), y(y_) {}
point operator+(const point &rhs) { return point(x + rhs.x, y + rhs.y); }
point operator-(const point &rhs) { return point(x - rhs.x, y - rhs.y); }
ll operator^(const point &rhs) const { return 1LL * x * rhs.y - 1LL * y * rhs.x; }
} pts[MAX_N];
int ans[MAX_N];
bool vis[MAX_N];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d%d", &pts[i].x, &pts[i].y);
scanf("%s", str + 1);
point remote = point(1e9, 1e9);
int remoteId;
for (int i = 1; i <= n; i++)
if (pts[i].x < remote.x || (pts[i].x == remote.x && pts[i].y < remote.y))
remote = pts[i], remoteId = i;
ans[1] = remoteId, vis[remoteId] = true;
for (int i = 2; i <= n; i++)
{
int pt = -1;
for (int j = 1; j <= n; j++)
if (!vis[j])
{
if (pt == -1)
pt = j;
else if ((str[i - 1] == 'L' && ((pts[j] - pts[remoteId]) ^ (pts[pt] - pts[remoteId])) > 0) ||
(str[i - 1] == 'R' && ((pts[j] - pts[remoteId]) ^ (pts[pt] - pts[remoteId])) < 0))
pt = j;
}
ans[i] = pt, vis[pt] = true, remoteId = pt;
}
for (int i = 1; i <= n; i++)
printf("%d ", ans[i]);
puts("");
return 0;
}
// route.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 5055;
typedef long long ll;
int n;
char str[MAX_N];
struct point
{
int x, y;
point(const int x_ = 0, const int y_ = 0) : x(x_), y(y_) {}
point operator+(const point &rhs) { return point(x + rhs.x, y + rhs.y); }
point operator-(const point &rhs) { return point(x - rhs.x, y - rhs.y); }
ll operator^(const point &rhs) const { return 1LL * x * rhs.y - 1LL * y * rhs.x; }
} pts[MAX_N];
int ans[MAX_N];
bool vis[MAX_N];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d%d", &pts[i].x, &pts[i].y);
scanf("%s", str + 1);
point remote = point(1e9, 1e9);
int remoteId;
for (int i = 1; i <= n; i++)
if (pts[i].x < remote.x || (pts[i].x == remote.x && pts[i].y < remote.y))
remote = pts[i], remoteId = i;
ans[1] = remoteId, vis[remoteId] = true;
for (int i = 2; i <= n; i++)
{
int pt = -1;
for (int j = 1; j <= n; j++)
if (!vis[j])
{
if (pt == -1)
pt = j;
else if ((str[i - 1] == 'L' && ((pts[j] - pts[remoteId]) ^ (pts[pt] - pts[remoteId])) > 0) ||
(str[i - 1] == 'R' && ((pts[j] - pts[remoteId]) ^ (pts[pt] - pts[remoteId])) < 0))
pt = j;
}
ans[i] = pt, vis[pt] = true, remoteId = pt;
}
for (int i = 1; i <= n; i++)
printf("%d ", ans[i]);
puts("");
return 0;
}
// route.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 5055; typedef long long ll; int n; char str[MAX_N]; struct point { int x, y; point(const int x_ = 0, const int y_ = 0) : x(x_), y(y_) {} point operator+(const point &rhs) { return point(x + rhs.x, y + rhs.y); } point operator-(const point &rhs) { return point(x - rhs.x, y - rhs.y); } ll operator^(const point &rhs) const { return 1LL * x * rhs.y - 1LL * y * rhs.x; } } pts[MAX_N]; int ans[MAX_N]; bool vis[MAX_N]; int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d%d", &pts[i].x, &pts[i].y); scanf("%s", str + 1); point remote = point(1e9, 1e9); int remoteId; for (int i = 1; i <= n; i++) if (pts[i].x < remote.x || (pts[i].x == remote.x && pts[i].y < remote.y)) remote = pts[i], remoteId = i; ans[1] = remoteId, vis[remoteId] = true; for (int i = 2; i <= n; i++) { int pt = -1; for (int j = 1; j <= n; j++) if (!vis[j]) { if (pt == -1) pt = j; else if ((str[i - 1] == 'L' && ((pts[j] - pts[remoteId]) ^ (pts[pt] - pts[remoteId])) > 0) || (str[i - 1] == 'R' && ((pts[j] - pts[remoteId]) ^ (pts[pt] - pts[remoteId])) < 0)) pt = j; } ans[i] = pt, vis[pt] = true, remoteId = pt; } for (int i = 1; i <= n; i++) printf("%d ", ans[i]); puts(""); return 0; }
B – infection
大概思考一下作为初始元素的贡献,发现是一段区间,然后就是区间覆盖问题。用个数据结构之类的维护一下 DP 即可。
// infection.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 4e5 + 200, mod = 1e9 + 7;
typedef pair<int, int> pii;
int n, dp[MAX_N], nodes[MAX_N], lower_side, preMax[MAX_N], sufMin[MAX_N];
pii pts[MAX_N], segs[MAX_N];
vector<int> vx, vv;
int lowbit(int x) { return x & (-x); }
void update(int x, int d)
{
for (; x <= lower_side; x += lowbit(x))
nodes[x] = (0LL + nodes[x] + mod + d) % mod;
}
int query(int x, int ret = 0)
{
for (; x; x -= lowbit(x))
ret = (0LL + ret + nodes[x]) % mod;
return ret;
}
int ripe(vector<int> &mp, int x) { return lower_bound(mp.begin(), mp.end(), x) - mp.begin() + 1; }
void solve()
{
for (int i = 1; i <= n; i++)
vx.push_back(pts[i].first), vv.push_back(pts[i].second);
sort(vx.begin(), vx.end()), sort(vv.begin(), vv.end());
for (int i = 1; i <= n; i++)
pts[i].first = ripe(vx, pts[i].first), pts[i].second = ripe(vv, pts[i].second);
lower_side = vv.size();
sort(pts + 1, pts + 1 + n);
for (int i = 1; i <= n; i++)
preMax[i] = max(preMax[i - 1], pts[i].second);
sufMin[n + 1] = 0x3f3f3f3f;
for (int i = n; i >= 1; i--)
sufMin[i] = min(sufMin[i + 1], pts[i].second);
for (int i = 1; i <= n; i++)
{
int up = preMax[i], lower = sufMin[i];
segs[i] = make_pair(lower, up);
}
sort(segs + 1, segs + 1 + n, [](const pii &A, const pii &B) { return A.second < B.second || (A.second == B.second && A.first < B.first); });
dp[0] = 1;
for (int i = 1; i <= n; i++)
{
int tmp = (0LL + query(segs[i].second) - query(segs[i].first - 1) + mod + dp[segs[i].first - 1]) % mod;
update(segs[i].second, tmp);
dp[segs[i].second] = (0LL + dp[segs[i].second] + tmp) % mod;
}
printf("%d\n", dp[lower_side]);
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d%d", &pts[i].first, &pts[i].second);
solve();
return 0;
}
// infection.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 4e5 + 200, mod = 1e9 + 7;
typedef pair<int, int> pii;
int n, dp[MAX_N], nodes[MAX_N], lower_side, preMax[MAX_N], sufMin[MAX_N];
pii pts[MAX_N], segs[MAX_N];
vector<int> vx, vv;
int lowbit(int x) { return x & (-x); }
void update(int x, int d)
{
for (; x <= lower_side; x += lowbit(x))
nodes[x] = (0LL + nodes[x] + mod + d) % mod;
}
int query(int x, int ret = 0)
{
for (; x; x -= lowbit(x))
ret = (0LL + ret + nodes[x]) % mod;
return ret;
}
int ripe(vector<int> &mp, int x) { return lower_bound(mp.begin(), mp.end(), x) - mp.begin() + 1; }
void solve()
{
for (int i = 1; i <= n; i++)
vx.push_back(pts[i].first), vv.push_back(pts[i].second);
sort(vx.begin(), vx.end()), sort(vv.begin(), vv.end());
for (int i = 1; i <= n; i++)
pts[i].first = ripe(vx, pts[i].first), pts[i].second = ripe(vv, pts[i].second);
lower_side = vv.size();
sort(pts + 1, pts + 1 + n);
for (int i = 1; i <= n; i++)
preMax[i] = max(preMax[i - 1], pts[i].second);
sufMin[n + 1] = 0x3f3f3f3f;
for (int i = n; i >= 1; i--)
sufMin[i] = min(sufMin[i + 1], pts[i].second);
for (int i = 1; i <= n; i++)
{
int up = preMax[i], lower = sufMin[i];
segs[i] = make_pair(lower, up);
}
sort(segs + 1, segs + 1 + n, [](const pii &A, const pii &B) { return A.second < B.second || (A.second == B.second && A.first < B.first); });
dp[0] = 1;
for (int i = 1; i <= n; i++)
{
int tmp = (0LL + query(segs[i].second) - query(segs[i].first - 1) + mod + dp[segs[i].first - 1]) % mod;
update(segs[i].second, tmp);
dp[segs[i].second] = (0LL + dp[segs[i].second] + tmp) % mod;
}
printf("%d\n", dp[lower_side]);
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d%d", &pts[i].first, &pts[i].second);
solve();
return 0;
}
// infection.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 4e5 + 200, mod = 1e9 + 7; typedef pair<int, int> pii; int n, dp[MAX_N], nodes[MAX_N], lower_side, preMax[MAX_N], sufMin[MAX_N]; pii pts[MAX_N], segs[MAX_N]; vector<int> vx, vv; int lowbit(int x) { return x & (-x); } void update(int x, int d) { for (; x <= lower_side; x += lowbit(x)) nodes[x] = (0LL + nodes[x] + mod + d) % mod; } int query(int x, int ret = 0) { for (; x; x -= lowbit(x)) ret = (0LL + ret + nodes[x]) % mod; return ret; } int ripe(vector<int> &mp, int x) { return lower_bound(mp.begin(), mp.end(), x) - mp.begin() + 1; } void solve() { for (int i = 1; i <= n; i++) vx.push_back(pts[i].first), vv.push_back(pts[i].second); sort(vx.begin(), vx.end()), sort(vv.begin(), vv.end()); for (int i = 1; i <= n; i++) pts[i].first = ripe(vx, pts[i].first), pts[i].second = ripe(vv, pts[i].second); lower_side = vv.size(); sort(pts + 1, pts + 1 + n); for (int i = 1; i <= n; i++) preMax[i] = max(preMax[i - 1], pts[i].second); sufMin[n + 1] = 0x3f3f3f3f; for (int i = n; i >= 1; i--) sufMin[i] = min(sufMin[i + 1], pts[i].second); for (int i = 1; i <= n; i++) { int up = preMax[i], lower = sufMin[i]; segs[i] = make_pair(lower, up); } sort(segs + 1, segs + 1 + n, [](const pii &A, const pii &B) { return A.second < B.second || (A.second == B.second && A.first < B.first); }); dp[0] = 1; for (int i = 1; i <= n; i++) { int tmp = (0LL + query(segs[i].second) - query(segs[i].first - 1) + mod + dp[segs[i].first - 1]) % mod; update(segs[i].second, tmp); dp[segs[i].second] = (0LL + dp[segs[i].second] + tmp) % mod; } printf("%d\n", dp[lower_side]); } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d%d", &pts[i].first, &pts[i].second); solve(); return 0; }
C – gcd
打表发现跟 Fibonacci 数列有关。可以用几个基底来算次数之类的。
// gcd.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e5 + 200, mod = 1e9 + 7;
typedef long long ll;
typedef pair<ll, ll> pll;
int n, q;
ll f[MAX_N];
vector<pll> g[MAX_N];
ll calc(pll u, ll x, ll y)
{
ll ret = 0;
if (x >= u.second && y >= u.first + u.second)
ret = (0LL + ret + (y - u.first) / u.second) % mod;
if (y >= u.second && x >= u.first + u.second)
ret = (0LL + ret + (x - u.first) / u.second) % mod;
return ret;
}
int main()
{
f[0] = f[n = 1] = 1;
while (f[n] <= 4e18)
n++, f[n] = f[n - 1] + f[n - 2];
for (int i = 1; i <= 2; i++)
g[0].push_back(make_pair(0, i));
for (int i = 0; i < n - 2; i++)
for (auto u : g[i])
{
ll x = u.first, y = u.second;
x += y;
while (x <= f[i + 3] + f[i])
{
if (x > y)
g[i + 1].push_back(make_pair(y, x));
x += y;
}
}
scanf("%d", &q);
while (q--)
{
ll x, y;
scanf("%lld%lld", &x, &y);
if (x < y)
swap(x, y);
ll ans = 1, sum = 0;
for (; f[ans + 2] <= x && f[ans + 1] <= y; ans++)
;
if (ans == 1)
sum = 1LL * x * y % mod;
else
for (auto &u : g[ans - 1])
sum = (0LL + sum + calc(u, x, y)) % mod;
printf("%lld %lld\n", ans, sum);
}
return 0;
}
// gcd.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e5 + 200, mod = 1e9 + 7;
typedef long long ll;
typedef pair<ll, ll> pll;
int n, q;
ll f[MAX_N];
vector<pll> g[MAX_N];
ll calc(pll u, ll x, ll y)
{
ll ret = 0;
if (x >= u.second && y >= u.first + u.second)
ret = (0LL + ret + (y - u.first) / u.second) % mod;
if (y >= u.second && x >= u.first + u.second)
ret = (0LL + ret + (x - u.first) / u.second) % mod;
return ret;
}
int main()
{
f[0] = f[n = 1] = 1;
while (f[n] <= 4e18)
n++, f[n] = f[n - 1] + f[n - 2];
for (int i = 1; i <= 2; i++)
g[0].push_back(make_pair(0, i));
for (int i = 0; i < n - 2; i++)
for (auto u : g[i])
{
ll x = u.first, y = u.second;
x += y;
while (x <= f[i + 3] + f[i])
{
if (x > y)
g[i + 1].push_back(make_pair(y, x));
x += y;
}
}
scanf("%d", &q);
while (q--)
{
ll x, y;
scanf("%lld%lld", &x, &y);
if (x < y)
swap(x, y);
ll ans = 1, sum = 0;
for (; f[ans + 2] <= x && f[ans + 1] <= y; ans++)
;
if (ans == 1)
sum = 1LL * x * y % mod;
else
for (auto &u : g[ans - 1])
sum = (0LL + sum + calc(u, x, y)) % mod;
printf("%lld %lld\n", ans, sum);
}
return 0;
}
// gcd.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 1e5 + 200, mod = 1e9 + 7; typedef long long ll; typedef pair<ll, ll> pll; int n, q; ll f[MAX_N]; vector<pll> g[MAX_N]; ll calc(pll u, ll x, ll y) { ll ret = 0; if (x >= u.second && y >= u.first + u.second) ret = (0LL + ret + (y - u.first) / u.second) % mod; if (y >= u.second && x >= u.first + u.second) ret = (0LL + ret + (x - u.first) / u.second) % mod; return ret; } int main() { f[0] = f[n = 1] = 1; while (f[n] <= 4e18) n++, f[n] = f[n - 1] + f[n - 2]; for (int i = 1; i <= 2; i++) g[0].push_back(make_pair(0, i)); for (int i = 0; i < n - 2; i++) for (auto u : g[i]) { ll x = u.first, y = u.second; x += y; while (x <= f[i + 3] + f[i]) { if (x > y) g[i + 1].push_back(make_pair(y, x)); x += y; } } scanf("%d", &q); while (q--) { ll x, y; scanf("%lld%lld", &x, &y); if (x < y) swap(x, y); ll ans = 1, sum = 0; for (; f[ans + 2] <= x && f[ans + 1] <= y; ans++) ; if (ans == 1) sum = 1LL * x * y % mod; else for (auto &u : g[ans - 1]) sum = (0LL + sum + calc(u, x, y)) % mod; printf("%lld %lld\n", ans, sum); } return 0; }