Loading [MathJax]/extensions/tex2jax.js

「FZOI」OI 周赛 #6 Div.0 – 题解

做起来很舒适的一套题。

A – route

假设一个局面:所有可用的点都已经在一侧,那么我们向那一侧走的时候,根据下一次的走向来决定走近似直线还是 Z 字形(也就是取极角序最大或最小)。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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 即可。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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 数列有关。可以用几个基底来算次数之类的。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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;
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *