zoukankan      html  css  js  c++  java
  • bzoj 1780

    这是一道环上的问题,我们先将一个环展开,再复制一次。

    这样,任何一个合法方案一定对应在转换后的序列的一些连续的区间,使得它们的并的长度大于等于圈长。

    然后,我们将区间合并一下(就是将一些被其他区间包含的区间去掉)。

    假设某个答案的区间是r1,r2,r3,...rk,我们可以让ri为"与ri-1连接的右端点最靠右的区间“,明显这样不会不原来的答案劣。

    所以,一旦确定了起点,那么在该起点的情况下最优的覆盖圆环的方案就确定了,确定了区间,我们可以用倍增的思想来判断一串连续区间覆盖len最少需要多少个,(有点像跳跃式的LCA求法中用倍增的思想)。这个O(logn)可搞,然后枚举起点是O(n),总的复杂度是O(nlogn)。

    /**************************************************************
        Problem: 1780
        User: idy002
        Language: C++
        Result: Accepted
        Time:2124 ms
        Memory:33796 kb
    ****************************************************************/
     
    #include <cstdio>
    #include <vector>
    #include <algorithm>
    #define fprintf(...)
    #define maxn 200010
    #define maxp 18
    using namespace std;
     
    struct Rng {
        int lf, rg;
        Rng(){}
        Rng( int lf, int rg ):lf(lf),rg(rg){}
        bool operator<( const Rng &b ) const { return lf<b.lf || (lf==b.lf&&rg>b.rg); }
    };
     
    int len, n;
    Rng rng[maxn]; int tot;
    vector<int> stk;
    bool mark[maxn];
    int nxt[maxn][maxp+1], dis[maxn][maxp+1];
     
    int main() {
        scanf( "%d%d", &len, &n );
        for( int i=1,lf,ln; i<=n; i++ ) {
            scanf( "%d%d", &lf, &ln );
            rng[++tot] = Rng(lf,lf+ln);
        }
        for( int i=1,otot=tot; i<=otot; i++ ) 
            rng[++tot] = Rng( rng[i].lf+len, rng[i].rg+len );
        sort( rng+1, rng+1+tot );
        for( int i=1; i<=tot; i++ ) 
            if( !mark[i] ) {
                stk.push_back( i );
                fprintf( stderr, "Got [%d,%d]
    ", rng[i].lf, rng[i].rg );
                for( int j=i+1; j<=tot; j++ )
                    if( rng[j].rg<=rng[i].rg ) mark[j]=true;
                    else break;
            }
        for( int t=0; t<stk.size(); t++ ) {
            int u=stk[t];
            nxt[u][0] = u;
            dis[u][0] = 0;
            for( int tt=t+1; tt<stk.size(); tt++ ) {
                int v=stk[tt];
                if( rng[v].lf<=rng[u].rg ) {
                    nxt[u][0] = v;
                    dis[u][0] = rng[v].rg-rng[u].rg;
                } else break;
            }
        }
        for( int p=1; p<=maxp; p++ ) 
            for( int t=0; t<stk.size(); t++ ) {
                int u=stk[t];
                nxt[u][p] = nxt[nxt[u][p-1]][p-1];
                dis[u][p] = dis[u][p-1]+dis[nxt[u][p-1]][p-1];
            }
        /*
        for( int t=0; t<stk.size(); t++ ) {
            int u=stk[t];
            fprintf( stderr, "from [%d,%d]: 
    ", rng[u].lf, rng[u].rg );
            for( int p=0; p<=5; p++ )
                fprintf( stderr, "nxt[%d]=[%d,%d] dis[%d]=%d
    ", p, rng[nxt[u][p]].lf, rng[nxt[u][p]].rg, p, dis[u][p] );
            fprintf( stderr, "
    " );
        }
        */
        int ans=n;
        for( int t=0; t<stk.size(); t++ ) {
            int u=stk[t];
            int remain=len-(rng[u].rg-rng[u].lf);
            int tans = 1;
            for( int p=maxp; dis[u][0] && dis[u][0]<remain; p-- )
                if( dis[u][p]<remain ) {
                    remain-=dis[u][p];
                    tans += 1<<p;
                    u=nxt[u][p];
                }
            tans++;
            if( dis[u][0]==0 ) continue;
            fprintf( stderr, "from [%d,%d] got ans %d
    ", rng[u].lf, rng[u].rg, tans );
            if( tans<ans ) ans=tans;
        }
        printf( "%d
    ", ans );
    }
    View Code
  • 相关阅读:
    windows 下的 Apache SSL证书配置
    javascript xml字符串转为json对象
    php 服务端允许跨域访问
    前端自动化构建工具 gulp 学习笔记 一、
    mysql使用select语句导出表数据时,报error 1290解决方法
    批量操作系统服务的脚本(windows关闭服务脚本)
    Dism++备份还原系统
    Win10开启蓝屏信息记录及文件查看位置的方法
    MySql 8.0服务端安装后,用navicat12连接时报2059错误_解决
    软件测试之细节功能测试_注意点
  • 原文地址:https://www.cnblogs.com/idy002/p/4344190.html
Copyright © 2011-2022 走看看