CF-GYM-[2019 USP Try-outs] 部分题解
C - Crystal Matryoshkas
思路:
贪心策略:
首先使用(multiset<int>),这个优秀的容器来储存当前剩余的套娃重量。
假设当前要包含的套娃重量为(mathit X),那么:
如果存在比当前套碗重量轻的套娃,选择重量最小的那个套娃,假设重量为(sum),然后用容器一直查找第一个大于等于(sum)的套娃,然后迭代,直至不能再添加套娃,且总重量小于等于(mathit X)。
然后将总重量加上(mathit X),同样上述的迭代方法直至没有重量更大的套娃。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#include <sstream>
#include <bitset>
#include <unordered_map>
// #include <bits/stdc++.h>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), ' ', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define chu(x) if(DEBUG_Switch) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
ll poww(ll a, ll b) { if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a ;} a = a * a ; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("
");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("
");}}}
inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
void pvarr_int(int *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%d%c", arr[i], i == n ? '
' : ' ');}}
void pvarr_LL(ll *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%lld%c", arr[i], i == n ? '
' : ' ');}}
const int maxn = 1000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
#define DEBUG_Switch 0
int n, q;
multiset<int> st;
map<int, int> m;
int main()
{
#if DEBUG_Switch
freopen("C:\code\input.txt", "r", stdin);
#endif
//freopen("C:\code\output.txt","r",stdin);
n = readint();
q = readint();
repd(i, 1, n)
{
int x = readint();
m[i] = x;
st.insert(x);
}
char op;
int id, x;
std::vector<int> v;
int cnt = 0;
while (q--)
{
scanf("%c", &op);
if (op == '?')
{
cnt++;
if (cnt == 6)
{
cnt = 6;
}
id = readint();
ll cal = m[id];
st.erase(st.lower_bound(cal));
v.pb(cal);
int ans = 1;
int flag = 0;
ll now;
if (st.size())
{
now = *(st.begin());
if (now <= cal)
{
flag = 1;
v.pb(now);
st.erase(st.begin());
ans++;
}
}
while (st.size())
{
auto it = st.lower_bound(now);
if(it==st.end())
break;
ll y = *it;
if (now + y <= cal)
{
now += y;
ans++;
} else
{
break;
}
}
if (flag)
{
now += cal;
} else {
now = cal;
}
while (1)
{
auto it = st.lower_bound(now);
if (it != st.end())
{
ans++;
now += (*it);
} else
{
break;
}
}
printf("%d
", ans );
for (auto &Y : v)
{
st.insert(Y);
}
v.clear();
} else if (op == '+')
{
x = readint();
id = readint();
m[id] = x;
st.insert(x);
} else
{
id = readint();
x = m[id];
st.erase(st.lower_bound(x));
}
}
return 0;
}
G - Hunting leshys
题目有一个很重要的限制:
Once a leshy has a superior, it can't change. In other words, each leshy appears as inferior to other leshy only once.
即在关系网中,每一个节点最多只有一个直接的父节点。
那么每一个有关系的家族中一定是一个单向链结构,而唯一可能使当前单向链结构中的节点的答案更新的方式是给当前最终祖先加一个父节点,那么我们可以用并查集来维护(far_i)每一个节点(mathit i)当前指向的当前最终祖先,在寻找祖先的函数中对数组(far_i)进行路径压缩,同时用当前结构中的父节点来更新该节点的答案值即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#include <sstream>
#include <bitset>
#include <unordered_map>
// #include <bits/stdc++.h>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), ' ', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define chu(x) if(DEBUG_Switch) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
ll poww(ll a, ll b) { if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a ;} a = a * a ; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("
");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("
");}}}
inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
void pvarr_int(int *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%d%c", arr[i], i == n ? '
' : ' ');}}
void pvarr_LL(ll *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%lld%c", arr[i], i == n ? '
' : ' ');}}
const int maxn = 1000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
#define DEBUG_Switch 0
int far[maxn];
int a[maxn];
void dsu_init(int n)
{
repd(i, 0, n)
{
far[i] = i;
}
}
int findpar(int x)
{
if (x == far[x])
{
return x;
} else
{
int res = findpar(far[x]);
a[x] = min(a[x], a[far[x]]);
far[x] = res;
return res;
}
}
int n;
int main()
{
#if DEBUG_Switch
freopen("C:\code\input.txt", "r", stdin);
#endif
//freopen("C:\code\output.txt","r",stdin);
n = readint();
int m = readint();
repd(i, 1, n)
{
a[i] = readint();
}
dsu_init(n);
char op;
while (m--)
{
scanf("%c", &op);
if (op == '+')
{
int fa = readint();
int son = readint();
far[son] = fa;
} else
{
int x = readint();
findpar(x);
printf("%d
", a[x] );
}
}
return 0;
}
J-MasterCodeChef Russia
题目链接:https://codeforces.com/gym/102299/problem/J
思路:
(T(c, p) − I(c, p) ≤ t)
带入(T(c, p) = frac{s(c) + d(p)}{2},I(c, p) = c_t*p_t + c_i*p_i)
(s(c) = c_t^2 + c_i^2,d(p) = p_t^2 + p_i^2 .)
得:
(frac{c_t^2 + c_i^2+p_t^2 + p_i^2}{2}-(c_t*p_t + c_i*p_i)leq t)
两边同时乘以2,得到:
(c_t^2 + c_i^2+p_t^2 + p_i^2-2*c_t*p_t + 2*c_i*p_ileq 2*t)
((c_i-p_i)^2+(c_t-p_t)^2leq 2*t)
可以发现题目可以转化成给定(mathit n)个二维空间的点,坐标为((c_i,c_t)),让你发现可以点((p_i,p_t)),使其满足到达各个点的距离的最大值最小。
显然当((p_i,p_t))是给定n个点的最小圆覆盖的圆心时,左式取最小值(R^2),R为最小圆的半径
根据最小圆覆盖算法可以得到半径(mathit R),则(t=frac{R^2}{2})
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#include <sstream>
#include <bitset>
#include <ctime>
#include <random>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), ' ', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
ll poww(ll a, ll b) { if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a ;} a = a * a ; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("
");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("
");}}}
inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
const int maxn = 1000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
int n;
typedef double ld;
struct Point
{
double x, y;
Point() {}
Point(double _x, double _y)
{
x = _x; y = _y;
}
Point operator +(const Point &b)const
{
return Point(x + b.x, y + b.y);
}
Point operator -(const Point &b)const
{
return Point(x - b.x, y - b.y);
}
//虏忙禄媒
double operator ^(const Point &b)const
{
return x * b.y - y * b.x;
}
Point operator *(const double &b)const
{
return Point(x * b , y * b);
}
//碌茫禄媒
double operator *(const Point &b)const
{
return x * b.x + y * b.y;
}
//脠脝脭颅碌茫脨媒脳陋陆脟露脠B拢篓禄隆露脠脰碌拢漏拢卢潞贸x,y碌脛卤盲禄炉
void transXY(double B)
{
double tx = x, ty = y;
x = tx * cos(B) - ty * sin(B);
y = tx * sin(B) + ty * cos(B);
}
ld distance(Point bb)
{
// chu(sqrtl((x - bb.x) * (x - bb.x) + (y - bb.y) * (y - bb.y)));
return sqrt((x - bb.x) * (x - bb.x) + (y - bb.y) * (y - bb.y));
}
void show()
{
cout << fixed << setprecision(6) << x << "," << y << endl;
}
};
Point a[maxn];
struct Circle
{
Point center;
double r;
Circle() {}
Circle(Point c1, double r1) {
center = c1;
r = r1;
}
};
Circle makeCircumcircle( Point &a, Point &b, Point &c) {
// Mathematical algorithm from Wikipedia: Circumscribed circle
if ( fabs((a - b) ^ (a - c)) < eps) {
return Circle(a, 1e9);// (a,b)//(a,c)
}
double ox = (min(min(a.x, b.x), c.x) + max(min(a.x, b.x), c.x)) / 2;
double oy = (min(min(a.y, b.y), c.y) + max(min(a.y, b.y), c.y)) / 2;
double ax = a.x - ox, ay = a.y - oy;
double bx = b.x - ox, by = b.y - oy;
double cx = c.x - ox, cy = c.y - oy;
double d = (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by)) * 2;
if (fabs(d) < eps)
return Circle(a, 1e9);//
double x = ((ax * ax + ay * ay) * (by - cy) + (bx * bx + by * by) * (cy - ay) + (cx * cx + cy * cy) * (ay - by)) / d;
double y = ((ax * ax + ay * ay) * (cx - bx) + (bx * bx + by * by) * (ax - cx) + (cx * cx + cy * cy) * (bx - ax)) / d;
Point p(ox + x, oy + y);
double r = max(max(p.distance(a), p.distance(b)), p.distance(c));
// chu(r);
return Circle(p, r);
}
int main()
{
//freopen("D:\code\text\input.txt","r",stdin);
//freopen("D:\code\text\output.txt","w",stdout);
gbtb;
cin >> n;
repd(i, 1, n)
{
cin >> a[i].x >> a[i].y;
}
mt19937 rnd(time(0));
shuffle(a + 1, a + 1 + n, rnd);
Circle res = Circle(a[1], 0.0);
repd(i, 1, n)
{
if (res.center.distance(a[i]) > res.r)
{
res = Circle(a[i], 0.0);
repd(j, 1, i - 1)
{
if (res.center.distance(a[j]) > res.r)
{
res = Circle((a[i] + a[j]) * 0.5, a[i].distance(a[j]) * 0.5);
repd(k, 1, j - 1)
{
if (res.center.distance(a[k]) > res.r)
{
res = makeCircumcircle(a[i], a[j], a[k]);
}
}
}
}
}
}
cout << fixed << setprecision(10) << res.center.x << " " << res.center.y << " " << res.r*res.r * 0.5 << endl;
return 0;
}