zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    高德地图在h5项目中的集成(点标记)
    angular中点击页面任意地方让显示的元素消失
    关于echars中雷达图的一些配置
    部署项目到阿里云服务器上遇到的问题
    sql语句的简单记录
    C#中的数据类型
    原型和继承
    Git 命令行使用
    以前一直设置水平居中,现在我们来讨论一下图片居中的四种小技巧
    让盒子两端对齐小技巧 => inline-block
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/10108354.html
Copyright © 2011-2022 走看看