AtCoder Regular Contest 103 構造專場?
阿新 • • 發佈:2018-12-12
這場比賽除了T1全是構造題耶。。。 構造專場???
T1 給你n個數,要求奇數位,所有數相同,偶數位所有數相同,且相鄰兩個數不同,最少需要改變多少個數。
一開始題意看錯求了箇中位數。。。 其實你只用維護一個奇數位出現次數的最大值,次大值,偶數位出現次數的最大值,次大值即可。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; int _min(int x, int y) {return x < y ? x : y;} int _max(int x, int y) {return x > y ? x : y;} int read() { int s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar(); return s * f; } int a[110000], b[110000]; int main() { int n = read(); for(int i = 1; i <= n; i++) { int x = read(); if(i & 1) a[(i + 1) / 2] = x; else b[i / 2] = x; } sort(a + 1, a + n / 2 + 1), sort(b + 1, b + n / 2 + 1); int max1 = 0, p1, max2 = 0, p2, max3 = 0, p3, max4 = 0, p4, cc = 1; for(int i = 2; i <= n / 2 + 1; i++) { if(a[i] == a[i - 1]) cc++; else { if(cc > max1) max2 = max1, max1 = cc, p2 = p1, p1 = a[i - 1]; else if(cc > max2) max2 = cc, p2 = a[i - 1]; cc = 1; } } cc = 1; for(int i = 2; i <= n / 2 + 1; i++) { if(b[i] == b[i - 1]) cc++; else { if(cc > max3) max4 = max3, max3 = cc, p4 = p3, p3 = b[i - 1]; else if(cc > max4) max4 = cc, p4 = b[i - 1]; cc = 1; } } if(p1 != p3) printf("%d\n", n - max1 - max3); else { printf("%d\n", _min(n - max1 - max4, n - max3 - max2)); } return 0; }
T2 給你n個點,對於所有的點都從起點(0,0)出發,它們第i步走的長度都是一樣的,但方向可以不同,最多走40步,每一步長度不超過1e12。
我們考慮這樣一種方法的正確性。 從2 ^ 30開始往 2 ^ 0列舉,每次給絕對值較大的減去或加上 2 ^ k,那你想,這樣子每一次加減完之後x和y都會控制在2 ^ k以內,最後肯定是能減完的。 但有一個要注意的,就是你這樣走出來是奇數步,到最後偶數步點不能走完,判一下就可以了。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; int _min(int x, int y) {return x < y ? x : y;} int _max(int x, int y) {return x > y ? x : y;} int read() { int s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar(); return s * f; } struct node { int x, y; } a[1100]; char ans[1100][41]; int n, now, D[40]; void solve(int x) { ++now; D[now] = x; for(int i = 1; i <= n; i++) { if(abs(a[i].x) > abs(a[i].y)) { if(a[i].x > 0) ans[i][now] = 'R', a[i].x -= x; else ans[i][now] = 'L', a[i].x += x; } else { if(a[i].y > 0) ans[i][now] = 'U', a[i].y -= x; else ans[i][now] = 'D', a[i].y += x; } } } int main() { n = read(); for(int i = 1; i <= n; i++) a[i].x = read(), a[i].y = read(); for(int i = 30; i >= 0; i--) solve(1 << i); if(a[1].x || a[1].y) solve(1); for(int i = 1; i <= n; i++) { if(a[i].x || a[i].y) {puts("-1"); return 0;} } printf("%d\n", now); for(int i = 1; i <= now; i++) printf("%d ", D[i]); printf("\n"); for(int i = 1; i <= n; i++) printf("%s\n", ans[i] + 1); return 0; }
T3 給你一個字串要求你構造一個字串長度的樹,如果第i個位有1就表示要求割掉一條邊之後能分成一個大小為i的連通塊,0表示不能分成。
首先無解的情況你可以根據對稱性把他判掉。 然後又根據對稱性,你只用判小於等於n/2的即可。 從小到大列舉,對於一個i如果有1我們就要保證他有i的連通塊,而又不能有多餘的連通塊,於是你只用在當前的根節點掛一些長度為1的邊即可,然後換一個根節點繼續掛。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; int _min(int x, int y) {return x < y ? x : y;} int _max(int x, int y) {return x > y ? x : y;} int read() { int s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar(); return s * f; } char ss[110000]; int main() { scanf("%s", ss + 1); int n = strlen(ss + 1); if(ss[n] == '1') {puts("-1"); return 0;} if(ss[1] == '0') {puts("-1"); return 0;} for(int i = 1; i < n; i++) { if(ss[i] != ss[n - i]) {puts("-1"); return 0;} } int id = 1, now = 1, o = n - 1; for(int i = n / 2; i >= 1; i--) { if(ss[i] == '1') { for(int j = 1; j <= o - i + 1; j++) { printf("%d %d\n", now, ++id); } o = i - 1; now = id; } } return 0; }
T4 給你n個點它們每個點到所有點的距離之和,叫你構造出一棵合法的樹。
我考試時的想法是從一個距離和最小的點開始掛,因為最小的距離和是重心,但然後發現子節點不知道掛哪裡。。。 然後呢,其實你反過來想一想,如果我們從最底層的孩子節點開始掛就方便很多,因為他的tot也是固定的就是1,並且他只有一個父親,所以就很好做了。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
int _min(int x, int y) {return x < y ? x : y;}
int _max(int x, int y) {return x > y ? x : y;}
LL read() {
LL s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
struct edge {
int x, y, next;
} f[110000], e[110000]; int len, last[110000];
struct node {
LL x; int id;
} a[110000];
LL d[110000], sum;
int tot[110000];
bool cmp(node a, node b) {return a.x < b.x;}
void ins(int x, int y) {
e[++len].x = x, e[len].y = y;
e[len].next = last[x], last[x] = len;
}
void dfs(int x, int dis) {
sum += dis;
for(int k = last[x]; k; k = e[k].next) {
int y = e[k].y;
dfs(y, dis + 1);
}
}
int main() {
LL n = read();
for(LL i = 1; i <= n; i++) a[i].x = read(), a[i].id = i;
sort(a + 1, a + n + 1, cmp);
for(LL i = 1; i <= n; i++) d[i] = a[i].x;
for(LL i = 1; i <= n; i++) tot[i] = 1;
len = 0;
for(LL i = n; i > 1; i--) {
LL u = d[i] - n + 2 * tot[i];
int fa = lower_bound(d + 1, d + n + 1, u) - d;
if(d[fa] != u) {puts("-1"); return 0;}
f[++len].x = fa, f[len].y = i;
tot[fa] += tot[i];
} len = 0; for(int i = 1; i < n; i++) ins(f[i].x, f[i].y);
sum = 0; dfs(1, 0);
if(sum != d[1]) {puts("-1"); return 0;}
for(int i = 1; i < n; i++) printf("%d %d\n", a[f[i].x].id, a[f[i].y].id);
return 0;
}