zoukankan      html  css  js  c++  java
  • 2021牛客暑期多校训练营6

    2021牛客暑期多校训练营6

    F.Hamburger Steak

    • 题意

    给n个汉堡,m个锅,每个锅只能同时做一个汉堡,做第i个汉堡需要(a_i)的时间,并且每个汉堡最多只能被两个锅做,问在尽可能减少平均每口锅做汉堡的时间的条件下,每个汉堡的方案。

    • 思路

    一看,一想,wtf,好难啊,想了半天,在看,emmm,wc,签到题
    每个汉堡无论被几个锅做,都是(a_i)那么最大的时间就是(max(a_i , sum / m + (sum % m != 0)))
    然后直接写就行了。。

    code:

    
    int a[N];
    void solve(){
        int n,m;
        sc("%lld%lld", &n, &m);
        int sum = 0, maxn = 0;
        for(int i = 1;i <= n;i ++) {
            scanf("%lld", &a[i]);
            sum += a[i];
            maxn = max(maxn,a[i]);
        }
        int sz = max(maxn, sum / m + (sum % m != 0));
        int now = sz;
        int cnt = 1;
        for(int i = 1;i <= n;i ++) {
            if(now >= a[i]) {
                pr("1 %d %lld %lld
    ", cnt, sz - now, sz - now + a[i]);
                now -= a[i];
                if(!now) now = sz,cnt ++;
            }else {
                pr("2 %d %lld %lld %d %lld %lld
    ", cnt + 1, 0, a[i] - now, cnt, sz - now, sz);
                now = sz - (a[i] - now);
                cnt ++;
    //             if(!now) now += sz, cnt ++;
            }
        }
    }
    

    H.Hopping Rabbit

    • 题意

    一个二维坐标轴,兔子每次跳的距离是d,并且只向上下左右跳,你需要找到兔子的起始坐标,让他怎么跳都跳不到给出的陷阱中,陷阱为一个矩阵((x_i,y_i o x_j,y_j))(左下角到右上角)。

    • 思路

    扫描线,把空间上所有大小为d * d的矩形合并起来,然后扫一遍,看看有没有空的就行

    code :

    struct node {
        int l,r;
    };
    // sum维护区间最小值
    int sum[N << 2], laz[N << 2];
     
    void update(int u,int l,int r,int L,int R,int v) {
        if(L > r || l > R) return;
        if(L <= l && R >= r) {
            sum[u] += v;
            laz[u] += v;
            return;
        }
        int mid = l + r >> 1;
        if(L <= mid) update(u << 1, l, mid, L, R, v);
        if(R > mid) update(u << 1 | 1, mid + 1, r, L, R, v);
        sum[u] = min(sum[u << 1], sum[u << 1 | 1]) + laz[u];
        return;
    }
     
    int query(int u,int l,int r) {
        if(l == r) return l;
        int mid = l + r >> 1;
        if(laz[u] + sum[u << 1] == sum[u]) {
            return query(u << 1,l,mid);
        }else {
            return query(u << 1 | 1,mid + 1,r);
        }
    }
     
    vector<node> st[N], ed[N];
     
    void solve(){
        int n,d;
        cin >> n >> d;
        bool flag = true;
        for(int i = 1;i <= n;i ++) {
            int x1,x2,y1,y2;
            cin >> x1 >> y1 >> x2 >> y2;
    		// 精度问题
            x1 += d * INF,y1 += d * INF, y2 += d * INF, x2 += d * INF;
            vector<node> a,b;
            if(x2 - x1 >= d && y2 - y1 >= d) {
                flag = 0;
            }
            if(x2 - x1 >= d) {
                a.pb({0,d - 1});
            }else if((x2 - 1) % d >= x1 % d) {
                a.pb({x1 % d, (x2 - 1) % d});
            }else {
                a.pb({0,(x2 - 1) % d});
                a.pb({x1 % d, d - 1});
            }
     
            if(y2 - y1 >= d) {
                b.pb({0,d-1});
            }else if((y2 - 1) % d >= y1 % d) {
                b.pb({y1 % d, (y2 - 1) % d});
            }else {
                b.pb({0,(y2 - 1) % d});
                b.pb({y1 % d, d - 1});
            }
     
            for(auto sa : a) {
                for(auto sb : b) {
                    st[sa.l].pb(sb);
                    ed[sa.r + 1].pb(sb);
                }
            }
        }
        if(!flag) {
            cout << "NO" << endl;
            return;
        }
        for(int i = 0;i < d;i ++) {
            // 维护差分
            for(auto a : st[i]) {
                update(1,0,d-1,a.l,a.r,1);
            }
            for(auto b : ed[i]) {
                update(1,0,d-1,b.l,b.r,-1);
            }
            if(sum[1] == 0) {
                cout << "YES" << endl;
                cout << i << ' ' << query(1,0,d-1) << endl;
                return;
            }
        }
        cout << "NO" << endl;
    }
    

    I. Intervals on the Ring

    • 题意

    给你一个n,m,序列长度为n且(n,1)为相邻的,(1,3)表示(1,2,3), (3,1)表示(3,4,5,1), 并且给出m个区间,让你构造一个k个区间,令这k个区间的交集为给出的m个区间的并集。

    • 思路

    构造题,考场没想到简单的做法,所以写了贼长
    就是类似:
    110011001100110011
    连续1表示需要交集的部分,那么就这样构造, (5,2), (9,5),(13,10),(17,14)记录每一个连续的l,r即可,(r_i o l_{i-1})即可,最后特判最后一个和第一个是否相连即可。

    code:

    int a[N];
     
    vpi ans;
    void solve(){
        int n,m;
        cin >> n >> m;
        int l,r;
        ans.clear();
        for(int i = 1;i <= 2 * n;i ++) a[i] = 0;
        fep(i,1,m) { // 构建差分数组
            cin >> l >> r;
            if(l <= r) {
                a[l] ++, a[r + 1] --;
            }else {
                a[l] ++, a[r + n + 1] --;
            }
        }
        if(m == 1) {
            cout << "1" << endl << l << ' ' << r << endl;
            return;
        }
        for(int i = 1;i <= 2 * n;i ++) {
            a[i] += a[i - 1];
        }
        // 建立双指针
        l = 1,r = 0;
        while(l <= n && !a[l] && !a[l + n]) l ++;
        r = l;
        while(r <= n && (a[r] || a[r + n])) r ++;
        if(r > n) {
            cout << "1" << endl << l << ' ' << n << endl;
            return;
        }
        int now = r;
        r --;
        ans.pb({l,r});
        while(now <= n && (!a[now] && !a[now + n])) now ++;
        while(now <= n) {
            int i = now;
            while(i <= n && (a[i] || a[i + n])) i ++;
            ans.push_back({now,i - 1});
            now = i;
            while(now <= n && (!a[now] && !a[now + n])) now ++;
        }
        if(ans.size() == 1) {
            cout << "1" << endl;
            cout << ans[0].first << ' ' << ans[0].second << endl;
        }else {
            if((a[n] || a[n + n]) && (a[1] || a[1 + n])) {
                cout << ans.size() - 1 << endl;
                for(int i = 1;i < ans.size();i ++) {
                    cout << ans[i].first << ' ' << ans[i - 1].second << endl;
                }
            }else {
                cout << ans.size() << endl;
                for(int i = 1;i < ans.size();i ++) {
                    cout << ans[i].first << ' ' << ans[i - 1].second << endl;
                }
                cout << ans[0].first << ' ' << ans[ans.size() - 1].second << endl;
            }
        }
    }
    

    J.Defend Your Country

    • 题意

    给出一个无向连通图,每个点的权值为(w_i),那么当一个连通块中的点数为奇数个那么整个联通块的价值是-1*权值和,否则是+1 *权值和,让你通过删边来最大化整个图中的价值

    • 思路
    1. 如果当前整个图的点都是偶数个,那么答案直接是(sum_{1}^{n} w_i)
    2. 若为奇数个那么一定是将整个图变成 偶+1奇+偶 最优,那么令中间的奇数点最小即可。
    3. 那么首先,这个奇数点是割点,然后它去的边必须也是偶数的

    code:

    int n,m;
    ll w[N];
    int h[N], e[M], ne[M], idx;
    int dfn[N],low[N],times;
    int sz[N];
    
    ll res = 1e9 + 7;
    
    void add(int a,int b) {
        e[idx] = b,ne[idx] = h[a], h[a] = idx ++;
    }
    
    void tarjan(int u,int fa = -1) {
        dfn[u] = low[u] = ++ times;
        sz[u] = 1;
        bool ok = 1;
        for(int i = h[u];~i;i = ne[i]) {
            int j = e[i];
            if(j == fa) continue;
            if(!dfn[j]) {
                tarjan(j,u);
                low[u] = min(low[u],low[j]);
                if(u == 1) {
                    // 根节点是割点的情况
                    if(i != h[u] && sz[j] % 2) ok = 0;
                }
                else if(dfn[u] <= low[j] && sz[j] % 2) { // 割点
                    ok = 0;
                }
                sz[u] += sz[j];
            }else low[u] = min(low[u], dfn[j]);
        }
        if(ok) res = min(res, w[u]);
    }
    
    
    void solve(){
        n = rd(), m = rd();
        ll sum = 0;
        fep(i,1,n) w[i] = rd(), sum += w[i];
        idx = times = 0;
        res = 1e9 + 7;
        for(int i = 1;i <= n;i ++) {
            h[i] = -1;
            dfn[i] = 0;
            sz[i] = 0;
        }
        fep(i,1,m) {
            int a = rd(),b = rd();
            add(a,b);
            add(b,a);
        }
        if(n % 2 == 0) {
            cout << sum << endl;
            return;
        }
        // 寻找割点,令整个图分割成(偶奇偶)即可
        tarjan(1);
    
        ll ans = max(-sum, sum - 2 * res);
        pr("%lld
    ", ans);
    }
    
  • 相关阅读:
    ios开发之多线程---GCD
    三:新浪微博--主框架的搭建
    二:新浪微博:第三方框架管理工具CocoaPods的安装和使用
    PHP Fatal Error: call to undefined function mysql_connect() [duplicate]
    ZooKeeper 3.4.5 分布式环境搭建详解
    coreLocation说明,作者写的很用心,收藏
    动画设置参数,有数值,收藏了
    Java 设计模式——组合模式
    NSURL基本操作示例说明
    关于应用程序启动,你可能不知道的东西
  • 原文地址:https://www.cnblogs.com/darker-wxl/p/15091789.html
Copyright © 2011-2022 走看看