第六届 CCPC 秦皇岛
Contents
- Contest Info
- Solutions
- Problem A. A Greeting from Qinhuangdao
- Problem B. Bounding Wall
- Problem C. Cameraman
- Problem D. Defend City
- Problem E. Exam Results
- Problem F. Friendly Group
- Problem G. Good Number
- Problem H. Holy Sequence
- Problem I. Interstellar Hunter
- Problem J. Jewel Splitting
- Problem K. Kingdom’s Power
- Problem L. Lost Temple
Contest Info
Solved | A | B | C | D | E | F | G | H | I | J | K | L |
---|---|---|---|---|---|---|---|---|---|---|---|---|
5/12 | O | - | O | - | O | O | O | - | - | - | - | - |
- O 在比赛中通过
- Ø 赛后通过
- ! 尝试了但是失败了
- - 没有尝试
Solutions
Problem A. A Greeting from Qinhuangdao
Solved By Dup4. 9(+)
题意
给出
思路
Code
#include <bits/stdc++.h>
using namespace std;
int main() {
int _T;
cin >> _T;
for (int i = 1; i <= _T; ++i) {
printf("Case #%d: ", i);
int r, b;
scanf("%d%d", &r, &b);
if (r < 2)
puts("0/1");
else {
int A = r * (r - 1);
int B = (r + b) * (r + b - 1);
int _g = __gcd(A, B);
A /= _g;
B /= _g;
printf("%d/%d\n", A, B);
}
}
return 0;
}
Problem B. Bounding Wall
Upsolved By -.
题意
思路
Problem C. Cameraman
Solved By Dup4 & groggy_. -
题意
- 给出一个矩形,左下角是
, 右上角是 , 并且给出一个点 。 - 在矩形内部有
个点,现在要找个点射出去两条线,使得射线以及矩形围成的闭合区域只有 这个点。 - 现在要求两条射线与矩形围成的闭合区域中,矩形那部分的变长和最长。
思路
- 大力猜测要找的那个点就可以是
。 - 然后从
向其它点连射线,交矩形一个点。 - 对求出的点做直角排序。
- 我们直接直角排序发现过不了。
- 后来考虑每个点肯定在矩形的四条边上,那么我们对这四条边的上的点分别排序,最后找个方向合并起来。
- 然后计算相邻两点之间围成的变长和。
- 这里其实情况有很多种,但是如果加入矩形的四个角作为虚点。
- 那么相邻亮点肯定在矩形的一条边上,这个时候求距离很简单。
- 那么就转化成了两个实点之间相邻两点的边长和。
Code
#include <bits/stdc++.h>
using namespace std;
using db = long double;
#define dbg(x...) \
do { \
cout << #x << " -> "; \
err(x); \
} while (0)
void err() {
cout << endl;
}
template <class T, class... Ts>
void err(const T &arg, const Ts &...args) {
cout << arg << ' ';
err(args...);
}
const db eps = 1e-6;
int sgn(db x) {
if (fabs(x) < eps)
return 0;
return x < 0 ? -1 : 1;
}
const int N = 1e5 + 10;
int w, h, n;
struct Point {
db x, y;
int vis, tp;
Point(db x = 0, db y = 0, int vis = 1) : x(x), y(y), vis(vis) {}
void scan() {
scanf("%Lf%Lf", &x, &y);
}
Point operator-(const Point &b) const {
return Point(x - b.x, y - b.y);
}
bool operator<(const Point &b) const {
return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x;
}
db operator^(const Point &b) const {
return x * b.y - y * b.x;
}
db dis(Point b) {
return hypot(x - b.x, y - b.y);
}
db dis2(Point b) {
return (x - b.x) * (x - b.x) + (y - b.y) * (y - b.y);
}
} p;
struct Line {
Point s, e;
Line() {}
Line(Point s, Point e) : s(s), e(e) {}
};
struct Polygon {
vector<Point> p;
Polygon() {
p.clear();
}
Polygon(int n) {
p.clear();
p.resize(n);
}
void add(Point x) {
p.push_back(x);
}
int sze() {
return p.size();
}
Point &operator[](int x) {
return p[(x + sze()) % sze()];
}
struct cmpNorm {
Point p;
cmpNorm(Point p) : p(p) {}
bool operator()(Point a, Point b) {
int d = sgn((a - p) ^ (b - p));
if (d == 0) {
return sgn(a.dis2(p) - b.dis2(p)) < 0;
} else {
return d > 0;
}
}
};
void norm() {
Point mi = *p.begin();
for (int i = 1; i < sze(); ++i) mi = min(mi, p[i]);
sort(p.begin(), p.end(), cmpNorm(mi));
}
void norm(Point mi) {
sort(p.begin(), p.end(), cmpNorm(mi));
}
// int pointInConvex(Point q) {
// int l = 1, r = sze() - 2;
// while (r - l >= 0) {
// int mid = (l + r) >> 1;
// int a1 = sgn((p[mid] - p[0]))
// }
// }
} po, _po;
db dis(Point a) {
return (p.x - a.x) * (p.x - a.x) + (p.y - a.y) * (p.y - a.y);
}
Point getPoint(Point a) {
db dis_x = fabs(a.x - p.x);
db dis_y = fabs(a.y - p.y);
// cout<<dis_x<<' '<<dis_y<<endl;
if (a.x == p.x && a.y > p.y)
return Point(p.x, h);
else if (a.y == p.y && a.x > p.x)
return Point(w, p.y);
else if (a.x == p.x && a.y < p.y)
return Point(p.x, 0);
else if (a.y == p.y && a.x < p.x)
return Point(0, p.y);
else if (a.x > p.x && a.y > p.y) {
Point new1_a;
new1_a.x = w;
new1_a.y = p.y + (w - p.x) * dis_y / dis_x;
Point new2_a;
new2_a.x = p.x + (h - p.y) * dis_x / dis_y;
new2_a.y = h;
// cout<<dis(new1_a)<<' '<<dis(new2_a)<<endl;
// cout<<new1_a.x<<' '<<new1_a.y<<endl;
// cout<<new2_a.x<<' '<<new2_a.y<<endl;
if (sgn(dis(new1_a) - dis(new2_a)) <= 0)
return new1_a;
else
return new2_a;
} else if (a.x > p.x && a.y < p.y) {
Point new1_a;
new1_a.x = w;
new1_a.y = p.y - (w - p.x) * dis_y / dis_x;
Point new2_a;
new2_a.x = p.x + p.y * dis_x / dis_y;
new2_a.y = 0;
if (sgn(dis(new1_a) - dis(new2_a)) <= 0)
return new1_a;
else
return new2_a;
} else if (a.x < p.x && a.y > p.y) {
Point new1_a;
new1_a.x = 0;
new1_a.y = p.y + p.x * dis_y / dis_x;
Point new2_a;
new2_a.x = p.x - (h - p.y) * dis_x / dis_y;
new2_a.y = h;
if (sgn(dis(new1_a) - dis(new2_a)) <= 0)
return new1_a;
else
return new2_a;
} else if (a.x < p.x && a.y < p.y) {
Point new1_a;
new1_a.x = 0;
new1_a.y = p.y - p.x * dis_y / dis_x;
Point new2_a;
new2_a.x = p.x - p.y * dis_x / dis_y;
new2_a.y = 0;
if (sgn(dis(new1_a) - dis(new2_a)) <= 0)
return new1_a;
else
return new2_a;
}
return Point(0, 0);
}
db calc(Point a, Point b) {
if (sgn(a.x - b.x) == 0 || sgn(a.y - b.y) == 0) {
return max(fabs(a.x - b.x), fabs(a.y - b.y));
} else {
assert(0);
}
return 0;
}
int main() {
int _T;
scanf("%d", &_T);
for (int CAS = 1; CAS <= _T; ++CAS) {
printf("Case #%d: ", CAS);
scanf("%d%d", &w, &h);
p.scan();
scanf("%d", &n);
po = Polygon(n);
for (int i = 0; i < n; ++i) {
po[i - 1].scan();
}
po.norm(p);
_po = Polygon(n + 4);
// dbg(n);
for (int i = 0; i < n; ++i) {
_po[i] = getPoint(po[i]);
// dbg(_po[i].x, _po[i].y);
_po[i].vis = 1;
}
_po[n] = Point(0, 0, 0);
_po[n + 1] = Point(w, 0, 0);
_po[n + 2] = Point(w, h, 0);
_po[n + 3] = Point(0, h, 0);
for (int i = 0; i < n + 4; ++i) {
if (sgn(_po[i].y) == 0)
_po[i].tp = 1;
else if (sgn(_po[i].x - w) == 0)
_po[i].tp = 2;
else if (sgn(_po[i].y - h) == 0)
_po[i].tp = 3;
else if (sgn(_po[i].x) == 0)
_po[i].tp = 4;
}
sort(_po.p.begin(), _po.p.end(), [&](Point a, Point b) {
if (a.tp != b.tp)
return a.tp < b.tp;
if (a.tp == 1)
return sgn(a.x - b.x) <= 0;
else if (a.tp == 2)
return sgn(a.y - b.y) <= 0;
else if (a.tp == 3)
return sgn(a.x - b.x) >= 0;
else if (a.tp == 4)
return sgn(a.y - b.y) >= 0;
});
// for (int i = 1; i <= n + 4; ++i) {
// dbg(i, _po[i].x, _po[i].y);
// }
db res = 0;
for (int i = 1; i <= n + 100; ++i) {
int _j = i - 1;
for (int j = i - 1;; --j) {
if (_po[j].vis == 1) {
_j = j;
break;
}
}
db now = 0;
for (int j = i - 1; j >= _j; --j) {
now += calc(_po[j], _po[j + 1]);
}
res = max(res, now);
}
printf("%.10Lf\n", res);
}
return 0;
}
Problem D. Defend City
Upsolved By -.
题意
思路
Problem E. Exam Results
Solved By Dup4 & ltslts. 76(+1)
题意
- 给出
个人和一个概率参数 。 - 对于每个人,在一场考试中,如果他发挥的好,他会得到
的分数,否则得到 的分数。 - 在一场考试中,假定最高分数为
,那么只要一个人得到的分数大于等于 ,那么他就能通过这场考试。 - 问所有
的情况中,最多能有多少人通过考试。
思路
- 将所有分数排序。
- 然后从大到小枚举
,然后维护两个指针。 - 一个是要所有大于
的分数都不能要。 - 一个是所有小于
的分数都不能加入。 - 但是考虑
是递减的,所以下界是逐渐减小,所以是慢慢加入很多可以的点。
- 但是考虑
- 所以每个分数只会被加入一次,剔除一次。
- 一个是要所有大于
- 要注意的是,如果一个人两个分数都因为大于
而被剔除掉,是不合法的情况。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pII = pair<int, int>;
#define fi first
#define se second
#define SZ(x) (int(x.size()))
const int N = 2e5 + 10;
int n, p;
int a[N], b[N];
int f[N];
void gao() {
for (int i = 1; i <= n; ++i) f[i] = 0;
vector<pII> vec;
for (int i = 1; i <= n; ++i) {
vec.push_back(pII(a[i], i));
vec.push_back(pII(b[i], i));
}
sort(vec.begin(), vec.end());
int res = 0, now = 0;
int r = SZ(vec) - 1, l = SZ(vec) - 1;
int m = SZ(vec) - 1;
int MaxScore = 0;
for (int i = 1; i <= n; ++i) {
MaxScore = max(MaxScore, min({a[i], b[i]}));
}
for (int i = m; i >= 0; --i) {
int Max = vec[i].fi;
if (Max < MaxScore)
break;
ll pMax = 1ll * p * Max;
while (l >= 0 && 1ll * vec[l].fi * 100 >= pMax) {
int id = vec[l].se;
++f[id];
if (f[id] == 1)
++now;
--l;
}
while (r >= 0 && vec[r].fi > Max) {
int id = vec[r].se;
--f[id];
if (f[id] == 0)
--now;
--r;
}
res = max(res, now);
}
printf("%d\n", res);
}
int main() {
int _T;
scanf("%d", &_T);
for (int CAS = 1; CAS <= _T; ++CAS) {
printf("Case #%d: ", CAS);
scanf("%d%d", &n, &p);
for (int i = 1; i <= n; ++i) {
scanf("%d%d", a + i, b + i);
}
gao();
}
return 0;
}
Problem F. Friendly Group
Solved By Dup4 & ltslts. 44(+)
题意
给出
现在要给出一个子图,定义价值为:
问如何选子图,使得价值最大?
思路
- 贪心,选择正收益的每一个连通块。
Code
#include <bits/stdc++.h>
using namespace std;
#define SZ(x) (int(x.size()))
const int N = 3e5 + 10;
int n, m;
vector<vector<int>> G, T;
struct UFS {
int fa[N], sze[N];
void init(int n) {
for (int i = 1; i <= n; ++i) {
fa[i] = 0;
sze[i] = 1;
}
}
int find(int u) {
return fa[u] ? fa[u] = find(fa[u]) : u;
}
void merge(int u, int v) {
int fu = find(u), fv = find(v);
if (fu != fv) {
if (sze[fu] > sze[fv]) {
swap(fu, fv);
}
fa[fv] = fu;
sze[fu] += sze[fv];
}
}
} ufs;
int main() {
int _T;
scanf("%d", &_T);
for (int CAS = 1; CAS <= _T; ++CAS) {
printf("Case #%d: ", CAS);
scanf("%d%d", &n, &m);
G.clear();
G.resize(n + 1);
ufs.init(n);
for (int i = 1, u, v; i <= m; ++i) {
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
ufs.merge(u, v);
}
T.clear();
T.resize(n + 1);
for (int i = 1; i <= n; ++i) {
T[ufs.find(i)].push_back(i);
}
int res = 0;
for (int i = 1; i <= n; ++i) {
if (!T[i].empty()) {
int E = 0, V = SZ(T[i]);
for (auto &it : T[i]) {
E += SZ(G[it]);
}
E /= 2;
if (E - V > 0)
res += E - V;
}
}
printf("%d\n", res);
}
return 0;
}
Problem G. Good Number
Solved By Dup4. 34(+)
题意
- 给出
和 。 - 统计
中有多少个 满足 。
思路
的时候特判。 - 考虑
的种类只有 种。 - 那么对于
,它掌管的范围是 , 直接统计这个范围内有多少个 的倍数即可。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int n, k;
ll calc(int x) {
ll res = 1;
for (int i = 1; i <= k; ++i) {
res *= x;
if (res > n)
return n + 1;
}
return res;
}
ll gao(ll x, ll y) {
return y / x;
}
int main() {
int _T;
scanf("%d", &_T);
for (int CAS = 1; CAS <= _T; ++CAS) {
printf("Case #%d: ", CAS);
scanf("%d%d", &n, &k);
if (k == 1) {
printf("%d\n", n);
} else {
int limit = ceil(pow(n, 1.0 / k)) + 10;
limit = min(limit, n);
ll res = 0;
for (int i = 1; i <= limit; ++i) {
ll l = calc(i);
ll r = calc(i + 1);
if (l < r) {
res += gao(i, r - 1) - gao(i, l - 1);
}
}
printf("%lld\n", res);
}
}
return 0;
}
Problem H. Holy Sequence
Upsolved By -.
题意
思路
Problem I. Interstellar Hunter
Upsolved By -.
题意
思路
Problem J. Jewel Splitting
Upsolved By -.
题意
思路
Problem K. Kingdom’s Power
Upsolved By -.
题意
- 给出
个点的有根树,根为 。 - 在根结点,有无限个士兵。
- 每次可以调配一个士兵,向它相邻的点走一步。
- 问所有点都至少被一个士兵访问过的最小次数。
思路
Problem L. Lost Temple
Upsolved By -.
题意
思路
Last update: March 24, 2022
Created: March 23, 2022
Created: March 23, 2022