题解:
第一题:二分+贪心;二分距离上限,两端的人能从两端取就从两端取,这样可以为中间的做贡献;
#include<bits/stdc++.h>
using namespace std; const int M = 10005; int a[M], b[M], pos[M], x, n, m; bool id[M]; #define ll long long inline int ab(int a, int b){ if(a > b)return a - b; return b - a; } bool check(ll d){ memset(id, 0, sizeof(id)); int lf = 1, rg = m, i; for(i = 1; a[i] <= x && i <= n; i++){ int j; for(j = lf; j <= m; j++){ if(ab(a[i], b[j]) + pos[j] <= d){ id[j] = 1;lf = j + 1;break; } } if(j == m + 1)return 0; } for(int z = n; z >= i; z--){ int j; for(j = rg; j >= 1; j--){ if(id[j])continue; if(ab(a[z], b[j]) + pos[j] <= d){ id[j] = 1;rg = j - 1;break; } } if(!j)return 0; } return 1; } int tot; int main(){ freopen("keys.in","r",stdin); freopen("keys.out","w",stdout); int Z = 0, W = 0; scanf("%d%d%d", &n, &m, &x); for(int i = 1; i <= n; i++) scanf("%d", &a[i]), Z = max(Z, ab(x, a[i])); for(int i = 1; i <= m; i++) scanf("%d", &b[i]), Z = max(Z, ab(b[i], x)); sort(a + 1, a + 1 + n); sort(b + 1, b + 1 + m); for(int i = 1; i <= m; i++)pos[i] = ab(b[i], x); ll rg; if(1LL*(Z + W + b[m] - a[1]) > 2e9)rg = 2e9; else rg = Z + W + b[m] - a[1]; ll lf = 1; int ans; while(lf <= rg){ ll mid = (lf + rg) >> 1; if(check(mid))ans = mid, rg = mid - 1; else lf = mid + 1; } printf("%d\n", ans); }
第二题:线段树,我们发现数的先后相对顺序是不变的,所以每次查询序列中最小值,并删除;知道上次的位置,我们优先取他右边小的(如果和左边相同),同一区间的优先选左边;我写了两个小时的第二题,结果少打了一个等号;
#include<bits/stdc++.h>
using namespace std; const int M = 1e5 + 10; #define inf 1e9 + 7
#define ll long long
int n, x, a[M], pos[M]; struct cd{ int val, id; bool operator < (const cd &a)const{ if(a.val == val)return a.id > id; return a.val < val; } }q[M]; struct Node{ Node *ls, *rs; int sum, v, vin; inline void up(){ sum = ls->sum + rs->sum; if(ls->v <= rs->v)vin = ls->vin; else vin = rs->vin; v = min(ls->v, rs->v); } }pool[M << 2], *tail = pool, *root; Node * build(int l = 1, int r = n){ Node *nd = ++tail; if(l == r) nd->sum = 1, nd->v = a[l], nd->vin = l; else { int mid = (l + r) >> 1; nd->ls = build(l, mid); nd->rs = build(mid + 1, r); nd->up(); } return nd; } #define Ls nd->ls, l, mid
#define Rs nd->rs, mid + 1, r
int query1(int L, int R, Node * nd = root, int l = 1, int r = n){ if(L <= l && r <= R) return nd->sum; else { int mid = (l + r) >> 1; int ans = 0; if(L <= mid)ans += query1(L, R, Ls); if(R > mid)ans += query1(L, R, Rs); return ans; } } int query2(int L, int R, Node * nd = root, int l = 1, int r = n){ if(L <= l && r <= R) return nd->vin; else { int mid = (l + r) >> 1; int ans1 = 0, ans2 = 0; if(L <= mid)ans1 = query2(L, R, Ls); if(R > mid)ans2 = query2(L, R, Rs); if(a[ans1] <= a[ans2])return ans1; else return ans2; } } void add(int pos, Node * nd = root, int l = 1, int r = n){ if(l == r) nd->sum--, nd->v = inf, nd->vin = 0; else { int mid = (l + r) >> 1; if(pos <= mid)add(pos, Ls); else add(pos, Rs); nd->up(); } } int main(){ freopen("cards.in","r",stdin); freopen("cards.out","w",stdout); scanf("%d", &n); a[0] = inf; for(int i = 1; i <= n; i++){ scanf("%d", &a[i]); } root = build(); int lst = query2(1, n); ll sum = query1(1, lst); add(lst); for(int i = 2; i <= n; i++){ int pos1 = query2(lst, n); int pos2 = query2(1, lst); if(a[pos1] <= a[pos2]){ sum += 1LL*query1(lst, pos1); lst = pos1; add(pos1); } else { sum += 1LL*query1(1, pos2) + query1(lst, n); lst = pos2; add(pos2); } //printf("%I64d %d %d\n", sum, a[pos1], a[pos2]);
} printf("%I64d\n", sum); }
第三题:整除分块
#include<bits/stdc++.h> using namespace std; const int M = 105; #define ll long long int n; ll k, a[M]; vector <ll> vec; bool check(ll d){ ll ans = 0; for(int i = 1; i <= n; i++){ ll x = (a[i] + d - 1) / d; ans += d * x - a[i]; } return ans <= k; } void split(ll a){ vec.push_back(a); for(ll d = a; d > 0; ){ ll k = (a + d - 1) / d; ll res = (a + k - 1) / k; vec.push_back(res); d = res - 1; } } int main(){ freopen("bamboo.in","r",stdin); freopen("bamboo.out","w",stdout); scanf("%d%I64d", &n, &k); ll uni = 0; for(int i = 1; i <= n; i++){ scanf("%I64d", &a[i]); split(a[i]); } sort(vec.begin(), vec.end()); vec.erase( unique(vec.begin(), vec.end()), vec.end()); vec.push_back( 10000000000000ll ); int tot = vec.size(); for(int i = 0; i < tot; i++){ ll lf = vec[i], rg = vec[i + 1] - 1, ans = 0; while(lf <= rg){ ll mid = (lf + rg) >> 1; if(check(mid))ans = mid, lf = mid + 1; else rg = mid - 1; } uni = max(uni, ans); } printf("%I64d\n", uni); }