暑假第二十四测

题解:

第一题:二分+贪心;二分距离上限,两端的人能从两端取就从两端取,这样可以为中间的做贡献;

#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
", ans);
}
View Code

第二题:线段树,我们发现数的先后相对顺序是不变的,所以每次查询序列中最小值,并删除;知道上次的位置,我们优先取他右边小的(如果和左边相同),同一区间的优先选左边;我写了两个小时的第二题,结果少打了一个等号;

#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
", sum, a[pos1], a[pos2]);
    }
    printf("%I64d
", sum);
}
View Code

第三题:整除分块

#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
", uni);
}
View Code
原文地址:https://www.cnblogs.com/EdSheeran/p/9530002.html