[SCOI2015] 国旗计划

也许更好的阅读体验

D e s c r i p t i o n \mathcal{Description} Description
给一个长度为 m + 1 m +1 m+1的环,上面有 n n n条线段,问在第 i i i条线段必须被选中的条件下覆盖整个环最少需要多少线段,不存在线段覆盖线段的情况,注意是线段, [ 1 , 2 ] [1, 2] [1,2] [ 3 , 4 ] [3,4] [3,4]之间少了 [ 2 , 3 ] [2,3] [2,3]这一段
n ≤ 2 ∗ 1 0 5 ,   m < 1 0 9 n \le 2 * 10^5,\ m \lt 10^9 n2105, m<109

S o l u t i o n \mathcal{Solution} Solution
用倍增,预处理出一个类似 s t st st表的表出来
环的问题先倍长数组,然后将线段也双倍
将线段按照左端点大小排序,由于不存在线段覆盖情况,因此可以肯定没有两条线段有端点相等的情况,并且左端点更大的线段右端点也更大
f [ i ] [ j ] f[i][j] f[i][j]表示排序后第 i i i条线段开始往后挑选 2 j 2^j 2j条线段并且使得覆盖的长度最长,最后一条线段的序号
考虑状态转移时并不是直接等于 f [ f [ i ] [ j − 1 ] ] [ j − 1 ] f[f[i][j - 1]][j-1] f[f[i][j1]][j1],因为最后一条线段是已经被选了的,因此应该从下一条线段开始
这里的下一条线段并不是序号+1,而应该是左端点在最后一条线段右端点范围内的尽可能大的那一条
这是很明显的贪心,如果有多条线段可以和当前覆盖范围拼起来,当然选能够覆盖的更多的线段
我们可以预处理出 n x t [ i ] nxt[i] nxt[i],表示第 i i i条线段的下一条线段是哪一个,因为从左到右 n x t [ i ] nxt[i] nxt[i]只会越来越大,因此 O ( n ) O(n) O(n)就可以处理出来
转移方程就变成了 f [ i ] [ j ] = f [ n x t [ f [ i ] [ j − 1 ] ] ] [ j − 1 ] f[i][j] = f[nxt[f[i][j - 1]]][j - 1] f[i][j]=f[nxt[f[i][j1]]][j1]
查询时,我们用类似求 L C A LCA LCA那样的方法不断接近覆盖整个环但始终不覆盖,最后就能得出还差一条线段就可以覆盖环的结果

C o d e \mathcal{Code} Code

#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 400005;
const int lim = 21;
struct seg{
    int l, r, id;
}s[maxn];
int n, m;
int lg[maxn], mi[maxn], ans[maxn], nxt[maxn];
int f[maxn][lim];
bool cmp (seg x, seg y)
{
    return x.l < y.l;
}
void deal ()
{
    mi[0] = 1;
    for (int i = 1; i < lim; ++i)  mi[i] = mi[i - 1] << 1;
    for (int i = 1; i <= n; ++i)    f[i][0] = i;
    for (int p = 2, i = 1; i <= n; ++i) {
        while (p < n && s[p + 1].l <= s[i].r)    ++p;
        nxt[i] = p;
    }
    for (int i = 1; i <= lg[n]; ++i)
        for (int j = 1; j <= n; ++j) {
            if (n - j + 1 >= mi[i]) f[j][i] = f[nxt[f[j][i - 1]]][i - 1];//只需求前面n条线段的答案,因此第2n条线段是不可能被用上的,若f[j][i]被赋值为0就说明不需要用这么多线段就可以覆盖环了
            else break;
        }
}
int query (int x)
{
    int res = 0, lt = s[x].l;
    for (int i = lg[n - x + 1]; ~i; --i)
        if (f[x][i] && s[f[x][i]].r - lt + 1 <= m)//f[x][i]为0说明不需要跳这么远
            res += mi[i], x = nxt[f[x][i]];
    return res + 1;
}
int main ()
{
    scanf("%d%d", &n, &m);
    lg[0] = -1;
    for (int i = 1; i <= n; ++i) {
		scanf("%d%d", &s[i].l, &s[i].r);
        if (s[i].r < s[i].l)    s[i].r += m;
	}
    for (int i = 1; i <= n; ++i) {
        s[i + n].l = s[i].l + m;
        s[i + n].r = s[i].r + m;
	}
    n <<= 1;
    for (int i = 1; i <= n; ++i)    s[i].id = i, lg[i] = lg[i >> 1] + 1;
    sort(s + 1, s + n + 1, cmp);
    deal();
    for (int i = 1; i <= n / 2; ++i)
        ans[s[i].id] = query(i);
    n >>= 1;
    for (int i = 1; i <= n; ++i)    printf("%d ", ans[i]);
    return 0;
}

如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧

weixin151云匹面粉直供微信小程序+springboot后端毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
weixin295微信小程序选课系统+ssm后端毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值