• Luogu 4155 [SCOI2015]国旗计划


    BZOJ 4444

    倍增 + 贪心。

    发现是一个环,先按照套路把环断开复制一倍,这样子的话覆盖完整个环就相当于覆盖一条长度不小于$m$的链,注意这样子有一些区间在新的这条链上会出现两次。

    我们为了找到最小的满足要求的答案,在选择完一个区间$[l, r]$之后会选择左端点不超过$r$但是右端点尽量大的区间,因为题目保证了所有的区间不相互包含,这样子的话我们只要找到左端点最靠右的区间就可以了。

    用$f_{i, j}$表示$i$号区间向下跳$2^j$个区间能跳到的最后一个区间,接下来只要按照套路倍增一下就好了。

    注意弄一个最大的右端点(要足够大,我就是这样WA了两次……),使倍增的时候能停下来。

    时间复杂度$O(nlogn)$。

    实现的时候需要注意细节。

    #include <cstdio>
    #include <cstring>
    #include <climits>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    
    const int N = 4e5 + 5;
    const int Lg = 22;
    const int inf = INT_MAX;
    
    int n, m, tot = 0, ans[N], f[N][Lg];
    
    struct Seg {
        int l, r, id;
        
        friend bool operator < (const Seg &x, const Seg &y) {
            if(x.l != y.l) return x.l < y.l;
            else return x.r < y.r;
        }
            
    } a[N];
    
    template <typename T>
    inline void read(T &X) {
        X = 0; char ch = 0; T op = 1;
        for(; ch > '9' || ch < '0'; ch = getchar())
            if(ch == '-') op = -1;
        for(; ch >= '0' && ch <= '9'; ch = getchar())
            X = (X << 3) + (X << 1) + ch - 48; 
        X *= op;
    }
    
    inline int solve(int x) {
        int res = 2, pos = x;
        for(int i = 20; i >= 0; i--)
            if(f[pos][i] && a[f[pos][i]].r < a[x].l + m)
                pos = f[pos][i], res += (1 << i);
        return res;
    }
    
    int main() {
    //    freopen("3.in", "r", stdin);
    //    freopen("my.out", "w", stdout);
        
        read(n), read(m);
        for(int l, r, i = 1; i <= n; i++) {
            read(l), read(r);
            if(l > r) {
                r += m;
                a[++tot].l = l, a[tot].r = r, a[tot].id = i;
            } else {
                a[++tot].l = l, a[tot].r = r, a[tot].id = i;
                a[++tot].l = l + m, a[tot].r = r + m, a[tot].id = i;
            }
        }
        
        sort(a + 1, a + 1 + tot);
        a[tot + 1].r = inf;
        
        for(int j = 1, i = 1; i <= tot; i++) {
            for(; j <= tot && a[j + 1].l <= a[i].r; ++j);
            f[i][0] = j;
        }
        for(int j = 1; j <= 20; j++)
            for(int i = 1; i <= tot; i++)
                f[i][j] = f[f[i][j - 1]][j - 1];
        
        for(int i = 1; i <= tot; i++) {
            if(a[i].l > m) continue;
            ans[a[i].id] = solve(i);
        }
        
        for(int i = 1; i <= n; i++)
            printf("%d%c", ans[i], i == n ? '
    ' : ' ');
    //    printf("
    ");
        
        return 0;
    }
    View Code
  • 相关阅读:
    Java 中队列的使用
    C# 网络编程之豆瓣OAuth2.0认证具体解释和遇到的各种问题及解决
    Java虚拟机工作原理具体解释
    天将降大任于斯人也,必先苦其心志,劳其筋骨,饿其体肤,空乏其身,行拂乱其所为,所以动心忍性,增益其所不能
    U-BOOT 移植到友善之臂mini2440
    眼下最好的JSP分页技术
    StageFright框架流程解读
    Oracle Hints具体解释
    大学技术类书单
    工作日志2014-07-09
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/10108354.html
Copyright © 2020-2023  润新知