[SCOI2015]国旗计划

本文介绍了一个关于区间覆盖的问题:给定一个大小为m的环和n个互不相交的区间,对于每个区间,计算至少需要多少个区间来完全覆盖整个环。文章通过将环转化为链,并利用贪心策略和倍增优化方法来解决该问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://www.zybuluo.com/ysner/note/1219682

题面

有一个大小为\(m\)的环,其上有\(n\)个区间(互不包含)。对每个区间分别回答,如果必须使用该区间,最少需要多少区间才能完全覆盖环。

  • \(n\leq10^5,m\leq10^9\)

    解析

    套路般地破环成链。区间能复制的也复制一边。

贪心显然,寻找一区间的后继者时,选左端点尽可能靠右、却又小于该区间右端点的区间。
(其实由于互不包含这一条件,排序以后,各区间左端点、右端点都具有单调性,所以说选右端点尽可能靠右的区间也可以)
于是可以预处理出每个区间的后继者。

注意到\(m\leq10^9\),暴跳铁定\(GG\),用倍增优化一下(或者说离散化,但实际上还是要倍增)。

记得在最右边设个极大值防止它跳得听不下来。。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define re register
#define il inline
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=5e5+100;
int n,m,top,len,mx,f[25][N],tot;
struct dat
{
  int l,r,id;
  bool operator < (const dat &o) const {return (l<o.l)||(l==o.l&&r<o.r);}
}a[N];
int ans[N];
bool vis[N];
il ll gi()
{
  re ll x=0,t=1;
  re char ch=getchar();
  while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  if(ch=='-') t=-1,ch=getchar();
  while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  return x*t;
}
il int work(re int x)
{
  re int tar=a[x].l+m,now=x,res=0;
  fq(i,20,0)
    if(f[i][now]&&a[f[i][now]].r<tar) now=f[i][now],res+=(1ll<<i);
  return res+2;//开始区间和结束区间都没算
}
int main()
{
  tot=n=gi();m=gi();
  fp(i,1,n)
    {
      a[i].l=gi(),a[i].r=gi();a[i].id=i;
      if(a[i].l>a[i].r) a[i].r+=m;
      else a[++tot]=(dat){a[i].l+m,a[i].r+m,i};
    }
  sort(a+1,a+1+tot);a[tot+1].r=2e9;
  re int ysn=1;
  fp(i,1,tot)
    {
      while(ysn<=tot&&a[ysn+1].l<=a[i].r) ++ysn;
      f[0][i]=ysn;
    }
  fp(i,1,20) fp(j,1,tot) f[i][j]=f[i-1][f[i-1][j]];
  fp(i,1,tot) if(a[i].l<=m) ans[a[i].id]=work(i);
  fp(i,1,n) printf("%d ",ans[i]);puts("");
  return 0;
}

转载于:https://www.cnblogs.com/yanshannan/p/9338507.html

资源下载链接为: https://pan.quark.cn/s/9e7ef05254f8 行列式是线性代数的核心概念,在求解线性方程组、分析矩阵特性以及几何计算中都极为关键。本教程将讲解如何用C++实现行列式的计算,重点在于如何输出分数形式的结果。 行列式定义如下:对于n阶方阵A=(a_ij),其行列式由主对角线元素的乘积,按行或列的奇偶性赋予正负号后求和得到,记作det(A)。例如,2×2矩阵的行列式为det(A)=a11×a22-a12×a21,而更高阶矩阵的行列式可通过Laplace展开或Sarrus规则递归计算。 在C++中实现行列式计算时,首先需定义矩阵类或结构体,用二维数组存储矩阵元素,并实现初始化、加法、乘法、转置等操作。为支持分数形式输出,需引入分数类,包含分子和分母两个整数,并提供与整数、浮点数的转换以及加、减、乘、除等运算。C++中可借助std::pair表示分数,或自定义结构体并重载运算符。 计算行列式的函数实现上,3×3及以下矩阵可直接按定义计算,更大矩阵可采用Laplace展开或高斯 - 约旦消元法。Laplace展开是沿某行或列展开,将矩阵分解为多个小矩阵的行列式乘积,再递归计算。在处理分数输出时,需注意避免无限循环和除零错误,如在分数运算前先约简,确保分子分母互质,且所有计算基于整数进行,最后再转为浮点数,以避免浮点数误差。 为提升代码可读性和可维护性,建议采用面向对象编程,将矩阵类和分数类封装,每个类有明确功能和接口,便于后续扩展如矩阵求逆、计算特征值等功能。 总结C++实现行列式计算的关键步骤:一是定义矩阵类和分数类;二是实现矩阵基本操作;三是设计行列式计算函数;四是用分数类处理精确计算;五是编写测试用例验证程序正确性。通过这些步骤,可构建一个高效准确的行列式计算程序,支持分数形式计算,为C++编程和线性代数应用奠定基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值