【专题·线段覆盖系列】Codevs线段覆盖12345

线段覆盖1

给定x轴上的N(0<N<100)条线段,每个线段由它的二个端点a_I和b_I确定,I=1,2,……N.这些坐标都是区间(-999,999)的整数。有些线段之间会相互交叠或覆盖。请你编写一个程序,从给出的线段中去掉尽量少的线段,使得剩下的线段两两之间没有内部公共点。所谓的内部公共点是指一个点同时属于两条线段且至少在其中一条线段的内部(即除去端点的部分)。

输入描述 Input Description

    输入第一行是一个整数N。接下来有N行,每行有二个空格隔开的整数,表示一条线段的二个端点的坐标。

输出描述 Output Description

    输出第一行是一个整数表示最多剩下的线段数。

样例输入 Sample Input

3

6  3

1  3

2  5

样例输出 Sample Output

2

数据范围及提示 Data Size & Hint

0<N<100
线段覆盖2

题目描述 Description

数轴上有n条线段,线段的两端都是整数坐标,坐标范围在0~1000000,每条线段有一个价值,请从n条线段中挑出若干条线段,使得这些线段两两不覆盖(端点可以重合)且线段价值之和最大。

n<=1000

输入描述 Input Description

第一行一个整数n,表示有多少条线段。

接下来n行每行三个整数, ai bi ci,分别代表第i条线段的左端点ai,右端点bi(保证左端点<右端点)和价值ci。

输出描述 Output Description

输出能够获得的最大价值

样例输入 Sample Input

3

1 2 1

2 3 2

1 3 4

样例输出 Sample Output

4

数据范围及提示 Data Size & Hint

数据范围

对于40%的数据,n10

对于100%的数据,n1000

0<=ai,bi<=1000000

0<=ci<=1000000

线段覆盖3

题目描述 Description

在一个数轴上有n条线段,现要选取其中k条线段使得这k条线段两两没有重合部分(端点可以重合),问最大的k为多少。

 

 

 

输入描述 Input Description

输入格式

输入文件的第1行为一个正整数n,下面n行每行2个数字ai,bi,描述每条线段。

输出描述 Output Description

输出格式

  输出文件仅包括1个整数,为k的最大值

样例输入 Sample Input

3

0 2

2 4

1 3

样例输出 Sample Output

2

数据范围及提示 Data Size & Hint

数据范围

对于20%的数据,n10

对于50%的数据,n1000

对于70%的数据,n100000

对于100%的数据,n10000000ai<bi≤1000000

线段覆盖4

题目描述 Description

数轴上有n条线段,线段的两端都是整数坐标,坐标范围在0~1000000,每条线段有一个价值,请从n条线段中挑出若干条线段,使得这些线段两两不覆盖(端点可以重合)且线段价值之和最大。

输入描述 Input Description

第一行一个整数n,表示有多少条线段。

接下来n行每行三个整数, ai bi ci,分别代表第i条线段的左端点ai,右端点bi(保证左端点<右端点)和价值ci。

输出描述 Output Description

输出能够获得的最大价值

样例输入 Sample Input

3

1 2 1

2 3 2

1 3 4

样例输出 Sample Output

4

数据范围及提示 Data Size & Hint

n <= 1000000

0<=ai,bi<=1000000

0<=ci<=1000000

数据输出建议使用long long类型(Pascal为int64或者qword类型)

线段覆盖5

题目描述 Description

数轴上有n条线段,线段的两端都是整数坐标,坐标范围在0~10^18,每条线段有一个价值,请从n条线段中挑出若干条线段,使得这些线段两两不覆盖(端点可以重合)且线段价值之和最大。

输入描述 Input Description

第一行一个整数n,表示有多少条线段。

接下来n行每行三个整数, ai bi ci,分别代表第i条线段的左端点ai,右端点bi(保证左端点<右端点)和价值ci。

输出描述 Output Description

输出能够获得的最大价值

样例输入 Sample Input

3

1 2 1

2 3 2

1 3 4

样例输出 Sample Output

4

数据范围及提示 Data Size & Hint

n <= 1000000

0<=ai,bi<=10^18

0<=ci<=10^9

数据输出建议使用long long类型(Pascal为int64或者qword类型)

这五道题其实1和3是一类,2,4,5是一类
1.3的基本策略:贪心,定义答案ans=n,每找到一条覆盖的线段把ans-1就可以了。 

代码如下
 
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
struct number
{
    int x,y;
}num[1000001];
bool cmp(number a,number b)
{
    return a.x < b.x;
}
int main()
{
    int n;
    scanf("%d",&n);
    for (int i=0; i<n;i++)
    scanf("%d%d",&num[i].x,&num[i].y);
    sort(num,num+n,&cmp);
    int t=n;
    number tmp=num[0];
    for (int i=1;i<n;i++)
    {
        if(tmp.x<=num[i].x&&tmp.y>=num[i].y)//如果当前枚举的线段完全覆盖上一条线段
            {
                t--;
                tmp=num[i];
            }
        else 
      if(num[i].x<tmp.y&&num[i].y>tmp.y)//如果当前枚举的线段部分覆盖上一条线段
            {
                t--;
            }
        else//如果当前枚举的线段不覆盖上一条线段
            tmp=num[i];
    }
    printf("%d\n",t);
    return 0;
}


而至于2.4.5,他们所求的不是线段的条数而是最大价值
因此因该采用DP
DP方程
if (s[i].a>=s[i-1].b) s[i].c+=s[i-1].c;
  else s[i].c=max(s[i-1].c,s[i].c+s[binary_chop(i,1,s[i].a)].c);
(如果当前枚举线段不覆盖上一条紧邻的线段,当前价值直接加上上一条线段价值,否则在上一条线段价值和当前线段与不覆盖线段的价值之和中取较大值)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n;
struct line
{
 long long a,b,c;
}s[1000001];
int comp(line a,line b)
{
 return a.b<b.b;
}
unsigned long long ans[1000001];
int binary_chop(int l,int r,long long x)//为了提高效率手动写了一个二分查找
{
    swap(l,r);
    while(l<r)
 {
        int mid=(l+r)>>1;
        if(s[mid].b<=x)
        l=mid+1;
        else r=mid;
    }
 return l-1;
}
char * ptr =new char[100000000];
template <typename T>
inline void in(T &x){
 while(*ptr<'0'||*ptr>'9')++ptr;
 x=0;
 while(*ptr>47&&*ptr<58)x=x*10+*ptr++-'0';
}
main()
{
 ptr[fread(ptr,1,100000000,stdin)]='z';
 in(n);
 for (int i=1;i<=n;i++)
  in(s[i].a),in(s[i].b),in(s[i].c);
 sort(s+1,s+n+1,comp);
 for (int i=1;i<=n;i++)
 {
  if (s[i].a>=s[i-1].b) s[i].c+=s[i-1].c;
  else s[i].c=max(s[i-1].c,s[i].c+s[binary_chop(i,1,s[i].a)].c);
        ans[i]=s[i].c;
 }
 cout<<ans[n];
} 


由于线段覆盖5数据范围过大,导致读入速度慢,因此加入读入优化fread。
修改前,有一个点TLE而修改后大所有点耗时都已经进入1s以内.
水题记录。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值