Codeforces 433 Div.2(A、B、C、D)
A. Fraction
暴力遍历1-1000,取组成的真分数比值最大且分子分母gcd为1时更新答案
代码:
#include <stdio.h> #include <algorithm> #include <cstdlib> #include <cstring> #include <bitset> #include <string> #include <stack> #include <cmath> #include <queue> #include <set> #include <map> using namespace std; #define INF 0x3f3f3f3f #define LC(x) (x<<1) #define RC(x) ((x<<1)+1) #define MID(x,y) ((x+y)>>1) #define fin(name) freopen(name,"r",stdin) #define fout(name) freopen(name,"w",stdout) #define CLR(arr,val) memset(arr,val,sizeof(arr)) #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); typedef pair<int, int> pii; typedef long long LL; const double PI = acos(-1.0); int main(void) { int n; while (~scanf("%d", &n)) { double mm = 0; int aa, bb; for (int a = 1; a <= n; ++a) { for (int b = a + 1; b <= n; ++b) { if (a + b == n && a < b && (a * 1.0 / b) > mm && __gcd(a, b) == 1) { aa = a; bb = b; mm = a * 1.0 / b; } } } printf("%d %d\n", aa, bb); } return 0; }
B. Maxim Buys an Apartment
最好的情况是尽量放中间,每一个房子都可以造成两个good位置,这样一共有n/3个位置,如果k<=n/3则答案就是k*3,否则把剩余的位置先放到对答案没影响的,再放到对答案影响为1的地方。
代码:
#include <stdio.h> #include <iostream> #include <algorithm> #include <cstdlib> #include <cstring> #include <bitset> #include <string> #include <stack> #include <cmath> #include <queue> #include <set> #include <map> using namespace std; #define INF 0x3f3f3f3f #define LC(x) (x<<1) #define RC(x) ((x<<1)+1) #define MID(x,y) ((x+y)>>1) #define fin(name) freopen(name,"r",stdin) #define fout(name) freopen(name,"w",stdout) #define CLR(arr,val) memset(arr,val,sizeof(arr)) #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); typedef pair<int, int> pii; typedef long long LL; const double PI = acos(-1.0); int main(void) { LL n, k; while (cin >> n >> k) { if (k == 0 || k == n) puts("0 0"); else { if (n == 2) puts("1 1"); else { if (k <= (n / 3)) printf("1 %I64d\n", k * 2); else { LL need = n / 3; LL res = k - need; printf("1 %I64d\n", need * 2 - (res - (n - need * 3))); } } } } return 0; }
C. Planning
贪心枚举当前时间k,让1-k时间内花费最多的航班最优降落即可,弱比我想到的是线段树,而大牛都是set……
代码:
#include <stdio.h> #include <algorithm> #include <cstdlib> #include <cstring> #include <bitset> #include <string> #include <stack> #include <cmath> #include <queue> #include <set> #include <map> using namespace std; #define INF 0x3f3f3f3f #define LC(x) (x<<1) #define RC(x) ((x<<1)+1) #define MID(x,y) ((x+y)>>1) #define fin(name) freopen(name,"r",stdin) #define fout(name) freopen(name,"w",stdout) #define CLR(arr,val) memset(arr,val,sizeof(arr)) #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); typedef pair<int, int> pii; typedef long long LL; const double PI = acos(-1.0); const int N = 6e5 + 7; struct seg { int l, mid, r; int v, id; } T[N << 2]; int arr[N]; int Time[N]; inline void pushup(int k) { if (T[LC(k)].v > T[RC(k)].v) { T[k].v = T[LC(k)].v; T[k].id = T[LC(k)].id; } else { T[k].v = T[RC(k)].v; T[k].id = T[RC(k)].id; } } void build(int k, int l, int r) { T[k].l = l; T[k].r = r; T[k].mid = MID(l, r); if (l == r) { T[k].v = arr[l]; T[k].id = l; } else { build(LC(k), l, T[k].mid); build(RC(k), T[k].mid + 1, r); pushup(k); } } void update(int k, int x) { if (T[k].l == T[k].r) T[k].v = -INF; else { if (x <= T[k].mid) update(LC(k), x); else update(RC(k), x); pushup(k); } } int query(int k, int l, int r) { if (l <= T[k].l && T[k].r <= r) return T[k].id; else { if (r <= T[k].mid) return query(LC(k), l, r); else if (l > T[k].mid) return query(RC(k), l, r); else { int ll = query(LC(k), l, r); int rr = query(RC(k), l, r); if (arr[ll] > arr[rr]) return ll; else return rr; } } } int main(void) { int n, k, i; while (~scanf("%d%d", &n, &k)) { for (i = 1; i <= n; ++i) scanf("%d", &arr[i]); build(1, 1, n); LL ans = 0; for (i = k + 1; i <= k + n; ++i) { int pos = query(1, 1, min(i, n)); ans = ans + (LL)(arr[pos]) * (LL)(i - pos); update(1, pos); arr[pos] = -INF; Time[pos] = i; } printf("%I64d\n", ans); for (i = 1; i <= n; ++i) printf("%d%c", Time[i], " \n"[i == n]); } return 0; }
D. Jury Meeting
前缀+后缀思想,主要用两个二维数组pre和suf和维护当前某地最少花费的cost数组,用pre[i][0]表示当前到第i天为止所有能到达0点的人最少花费,pre[i][1]表示有几个人能到达0点,因此枚举i,把航班天数小于等于i的数据都拿去更新cost,再结合cost更新pre,类似于前缀最小值一样处理一遍,然后返程suf数组做一个与pre相反顺序的后缀最小花费处理,然后枚举到达和离开的区间[l,l+k+1],检查一下区间合法性和区间内是否可以到齐,再更新答案即可
代码;
#include <stdio.h> #include <iostream> #include <algorithm> #include <cstdlib> #include <cstring> #include <bitset> #include <string> #include <stack> #include <cmath> #include <queue> #include <set> #include <map> using namespace std; #define INF 0x3f3f3f3f #define LC(x) (x<<1) #define RC(x) ((x<<1)+1) #define MID(x,y) ((x+y)>>1) #define fin(name) freopen(name,"r",stdin) #define fout(name) freopen(name,"w",stdout) #define CLR(arr,val) memset(arr,val,sizeof(arr)) #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); typedef pair<int, int> pii; typedef long long LL; const double PI = acos(-1.0); const int N = 1000010; struct info { int d, s, t, c; }; info A[N], B[N]; LL pre[N][2], suf[N][2], cost[N]; void init() { CLR(pre, 0); CLR(suf, 0); } int main(void) { int n, m, k, i; while (~scanf("%d%d%d", &n, &m, &k)) { init(); int cnta = 0, cntb = 0; int maxday = 0; for (i = 0; i < m; ++i) { int d, s, t, c; scanf("%d%d%d%d", &d, &s, &t, &c); if (t == 0) A[cnta++] = (info) {d, s, t, c}; else B[cntb++] = (info) {d, s, t, c}; maxday = max(maxday, d); } sort(A, A + cnta, [](info a, info b) {return a.d < b.d;}); sort(B, B + cntb, [](info a, info b) {return a.d > b.d;}); LL ps = 0, pc = 0; int cur = 0; CLR(cost, 0); for (i = 1; i <= maxday; ++i) { while (A[cur].d <= i && cur < cnta) { if (!cost[A[cur].s]) { cost[A[cur].s] = A[cur].c; ps += A[cur].c; ++pc; } else if (cost[A[cur].s] > A[cur].c) { ps -= cost[A[cur].s]; ps += A[cur].c; cost[A[cur].s] = A[cur].c; } ++cur; } pre[i][0] = ps; pre[i][1] = pc; } cur = 0; ps = 0; pc = 0; CLR(cost, 0); for (i = maxday; i >= 1; --i) { while (B[cur].d >= i && cur < cntb) { if (!cost[B[cur].t]) { cost[B[cur].t] = B[cur].c; ps += B[cur].c; ++pc; } else if (cost[B[cur].t] > B[cur].c) { ps -= cost[B[cur].t]; ps += B[cur].c; cost[B[cur].t] = B[cur].c; } ++cur; } suf[i][0] = ps; suf[i][1] = pc; } LL ans = 0x3f3f3f3f3f3f3f3f; for (i = 1; i <= maxday; ++i) { if (i + k + 1 <= maxday && pre[i][1] >= n && suf[i + k + 1][1] >= n && pre[i][0] + suf[i + k + 1][0] < ans) ans = pre[i][0] + suf[i + k + 1][0]; } printf("%I64d\n", ans == 0x3f3f3f3f3f3f3f3f ? -1 : ans); } return 0; }