[Codeforces] Educational Codeforces Round 124 A~D
A. Playoff
大致题意是给出n,一共有2^n个人,两两进行比较,如果x+y是奇数,那么输出x,否则输出y
思路
除了第一轮输出的是x(都是奇数+偶数),剩下的输出的都是y(都是奇数+奇数),所以直接输出2^n-1
代码
int qmi(int m, int k)
{
int res = 1, t = m;
while (k)
{
if (k&1) res = res * t;
t = t * t;
k >>= 1;
}
return res;
}
void solve() {
int n;
cin >> n;
cout << qmi(2, n) - 1 << endl;
}
B. Prove Him Wrong
大致题意是说对给出的序列长度,构造一个进行一次操作ai = aj = |ai - aj|后序列总和不变或者增加的序列
思路
设ai=x, aj=y, 可解的y=3x,所以ai+1 = 3 * ai,当n>=20时,ai会大于1e9,不满足条件,所以只有在n=[1,19]才能进行构造,否则输出NO
代码
void solve() {
int n;
cin >> n;
int ans = 1;
if(n >= 20) {
cout << "NO" << endl;
return;
}
cout << "YES" << endl;
cout << 1 << " ";
for(int i = 2; i <= n; i ++) {
ans = ans * 3;
cout << ans << " ";
}
cout << endl;
}
C. Fault-tolerant Network
大致题意是给出两排电脑,每排相邻电脑间已经连接好了,我们需要连接两排的电脑成为同一个网络,让我们求当任意一台电脑瘫痪后,网络不会分裂成两个或多个的最小价值的连接方式
思路
挺折磨的一个分类讨论(调了好久才调出来)
首先要想到最小的连接方式,肯定是将四个角都连到对方网络上,这样才会构成一个环
再去找每个角连到对方网络的最小价值
以第一排第一个点为例,它的连接方式有三种,一是连接到第二排第二个点,二是连接到第二排最后一个点,三是连接到第二排中间的点,对此我们要判断它在哪一种情况下价值是最小的
最后我个人代码的分类是按四个角有没有竖直相连或者有没有交叉相连来判断最小值
代码可能有些冗余
代码
void solve() {
vector<ll> a, b;
int n;
cin >> n;
ll x;
for(int i = 1; i <= n; i ++) {
cin >> x;
a.push_back(x);
}
for(int i = 1; i <= n; i ++) {
cin >> x;
b.push_back(x);
}
ll ini = abs(a[0] - b[0]) + abs(a[a.size() - 1] - b[b.size() - 1]); //四个角竖直相连
ll x1 = a[0], x2 = a[a.size() - 1], x3 = b[0], x4 = b[b.size() - 1];
ll ans = 0, ans1 = 1e15, ans2 = 1e15, ans3 = 1e15, ans4 = 1e15;
bool fg1 = 0, fg2 = 0;
for(auto i : b) {
if(ans1 > abs(i - x1)) fg1 = i, ans1 = abs(i - x1); //找第一排第一个点连接的最小价值
}
//cout << ans1 << endl;
for(auto i : b) {
if(ans2 > abs(i - x2)) fg2 = i, ans2 = abs(i - x2); //找第一排最后一个点连接的最小价值
}
//cout << ans2 << endl;
for(auto i : a) {
if(ans3 > abs(i - x3)) ans3 = abs(i - x3); //找第二排第一个点连接的最小价值
}
for(auto i : a) {
if(ans4 > abs(i - x4)) ans4 = abs(i - x4); //找第二排最后一个点连接的最小价值
}
ll minn = abs(x4 - x1) + abs(x2 - x3); //四个角交叉相连
ll ansb = 0;
//求四个角没有交叉相连下的最小值
if(ans1 + ans3 < abs(x1 - x3)) ans += ans1 + ans3;
else ans += abs(x1 - x3);
if(ans2 + ans4 < abs(x2 - x4)) ans += ans2 + ans4;
else ans += abs(x2 - x4);
//求四个角没有竖直相连下的最小值
if(ans1 + ans4 < abs(x1 - x4)) ansb += ans1 + ans4;
else ansb += abs(x1 - x4);
if(ans2 + ans3 < abs(x2 - x3)) ansb += ans2 + ans3;
else ansb += abs(x2 - x3);
cout << min(ansb, min(minn, min(ans, ini))) << endl;
}
D. Nearest Excluded Points
大致题意是给出n个点,求离每个点最近的点(不是给出的点)的最短曼哈顿距离
思路
对于只有单个的点来看,距它最近的点肯定是它四个方向上的相邻点
对于多个点组成的点块,距它们最近的点肯定是它们周围的某个点
所以我们可以用bfs从外向内搜索,对于每个点更新它从哪个点更新而来的
map里用count函数来找是否存在这个数,直接用mp[{x, y}]!=0会出错?(也许是因为底层用的是红黑树的原因,具体不清楚,以后尽量用count吧)
代码
const int maxn = 2e5+5;
int dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0};
typedef pair<int, int> PII;
map<PII, int> idx;
map<pair<int, int> , int> vis;
map<PII, PII> frm;
queue<PII> que;
map<int, PII> ans;
int x[maxn], y[maxn];
signed main(signed argc, char const *argv[])
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
#ifdef LOCAL
freopen("in.in", "r", stdin);
freopen("out.out", "w", stdout);
#endif
//======================================
int n;
cin >> n;
for(int i = 1; i <= n; i ++) {
cin >> x[i] >> y[i];
idx[{x[i], y[i]}] = i;
}
for(int i = 1; i <= n; i ++) {
for(int j = 0; j < 4; j ++) {
int kx = x[i] + dx[j];
int ky = y[i] + dy[j];
if(!idx.count({kx, ky})) {
que.push({kx, ky});
frm[{kx, ky}] = {kx, ky};
}
}
}
while(que.size()) {
int xst = que.front().first;
int yst = que.front().second;
que.pop();
for(int k = 0; k < 4; k ++) {
int kx = xst + dx[k], ky = yst + dy[k];
if(idx.count({kx, ky}) && !vis[{kx, ky}]) {
vis[{kx, ky}] = 1;
frm[{kx, ky}] = frm[{xst, yst}];
ans[idx[{kx, ky}]] = frm[{xst, yst}];
que.push({kx, ky});
}
}
}
for(int i = 1; i <= n; i ++) {
cout << ans[i].first << " " << ans[i].second << endl;
}
//======================================
return 0;
}

浙公网安备 33010602011771号