暑假第二十四测

题解:

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

#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);
}

原文地址:https://www.cnblogs.com/EdSheeran/p/9530002.html

时间: 2024-10-23 00:29:22

暑假第二十四测的相关文章

暑假第二十五测

以后WA了T了看数组: 暑假四次数组下标超界,多次数组开小,暂时没有访问到负下标 题解: 第一题:这道题可以转换为颜色相同的点缩成一个点,每次可以将两个点合并成同一点,问最少几次将所有点合并成一个点: 开始想到并查集+贪心合并度数最多的并查集,但这样是有问题的,比如度数一样时,选择的先后顺序是有影响的: 正解:缩点+找直径,如果是一条黑白相间的链,就是点数/2, 而树上任何一条直径都会有一个点经过直径,我们从交点开始往外延伸,发现最长延伸就是直径本身: 思想:从特殊到一般 #include<bi

暑假第十四测

题解: 第一题:nlogn LIS #include<bits/stdc++.h> using namespace std; const int M = 100005; int a[M], f[M]; int main(){ freopen("lis.in","r",stdin); freopen("lis.out","w",stdout); int n, cnt = 0; scanf("%d"

暑假第二十六测

今天又考的奇差 题解: 第一题: 这么简单一道题我想了好久,智商实在是下线了: #include<bits/stdc++.h> using namespace std; int main(){ freopen("shortway.in","r",stdin); freopen("shortway.out","w",stdout); int n, k; scanf("%d%d", &n,

暑假第二十九测

第三题换成能否得到x, 可以1, 不可以-1 题解: 第一题:打表找规律: 打表发现a是:1 1 2 2 3 4 4 4 5 6 6 7 8 8 8 8 9-- 对于每一项Ai = i拆分成质因数中有多少个2 + 1:如果把桶也给打出来,就发现他是这样的: 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 2 + 4 + 6 + 8 +  4  + 8 +  8 + 即2^i的等差数列,所以对一个数m我们就很容易确定他前面的数的和: 但是对于一个位置我们怎么找到他对应的m呢? 把上

centos LNMP第二部分nginx、php配置 第二十四节课

centos  LNMP第二部分nginx.php配置  第二十四节课 上半节课 下半节课 f

centos mysql 优化 第二十四节课

centos mysql  优化  第二十四节课 f

第二十四课:能量和功率

1.RC电路充电过程的能量特性: 电源提供的能量  Vs i 在T内积分 如果T远远大于时间常数,则该能量等于 CVs2 但是电容储存的能量等于 (1/2) CVs2 因此一半能量被电阻消耗,另一半则被电容储存起来 2.RC电路放电过程的能量特性: 所以能量消耗在电阻上 3.将两个过程相连,则电源消耗CVs2,一般在充电时消耗,一般在放电时消耗 因此平均功率等于 CVs2f   ,f是充放电的切换频率,愈大功率越大 4.类似于MODFET反相电路 两种功率之和:待机功率和动态功率,后者就是充放电

javaSE第二十四天

第二十四天????363 1:多线程(理解)????363 (1)JDK5以后的Lock锁????363 A:定义????363 B:方法:????364 C:具体应用(以售票程序为例)????364 1,. SellTicket类????364 2,. SellTicketDemo测试类????365 (2)死锁问题的描述和代码体现????365 1. DieLockDemo测试类????365 2. DieLock类(该类继承自Thread)????366 3. MyLock(锁对象类)??

经典算法题每日演练——第二十四题 梳排序

原文:经典算法题每日演练--第二十四题 梳排序 这篇再看看一个经典的排序,梳排序,为什么取名为梳,可能每个梳都有自己的gap吧,大梳子gap大一点,小梳子gap小一点. 上一篇我们看到鸡尾酒排序是在冒泡排序上做了一些优化,将单向的比较变成了双向,同样这里的梳排序也是在冒泡排序上做了一些优化. 冒泡排序上我们的选择是相邻的两个数做比较,就是他们的gap为1,其实梳排序提出了不同的观点,如果将这里的gap设置为一定的大小, 效率反而必gap=1要高效的多. 下面我们看看具体思想,梳排序有这样一个1.