AtCoder Beginner Contest 103 - D Islands War (贪心)

题目

 

题意:

给你n个点,他们1到n依次从左到右连接。问你m对数(A,B)。AB不能相连。

问你最少要拆多少条边.

 

POINT:

O(m)的做法:

记录每一个左端点,与他有争议的最近的右端点。记为a数组(可以贪心的知道断每一个右端点是最优的)。

那么假设断的是a[1],如果往后扫的有争议的右端点(比如a[2])比a[1]大,那么就只要断a[1]就行了。

如果比a[1]小,那么断a[2]。

用了输入挂,必须文件输入

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <string>
#include <map>
#include <math.h>
using namespace std;
#define LL long long
 
 
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<22, stdin), p1 == p2) ? EOF : *p1++)
char buf[(1 << 22)], *p1 = buf, *p2 = buf;
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
 
 
 
int main()
{
    int n,m;
    int* a = new int[(int)1e7 + 10];
    n=read();
    m=read();
//  cin>>n>>m;
    int M=1e7+7;
    for(int i=1;i<=n;i++)
        a[i]=0;
    for(int i=1;i<=m;i++){
        int l,r;
        l=read();
        r=read();
//      cin>>l>>r;
        if(r<l) swap(r, l);
        M=min(M,l);
        if(a[l]!=0&&a[l]>r) a[l]=r;
        else if(a[l]==0) a[l]=r;
    }
    int ans=1;
    int k=a[M];
    for(int i=1;i<=n;i++){
        if(a[i]==0) continue;
        if(i>=k){
            ans++;
            k=a[i];
        }else if(k>a[i]){
            k=a[i];
        }
    }
    if(m==0) printf("0\n");
    else
        printf("%d\n",ans);
    return 0;
 
}

 

m*log(m)的做法:

R端点从左到右排序。然后看看L到R有没有拆至少一条边,有的话就不用拆了。

没有的话拆R这个点的边。

看L到R有没有拆边可以用树状数组实现log(N)的效率。

 

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <string>
#include <map>
using namespace std;
#define LL long long
const int maxn = 1e6+33;
const int mod = 1e9+7;

int num[maxn];

struct node
{
    int l,r;
    bool friend operator < (node a,node b){
        return a.r<b.r;
    }
}q[maxn];
int n,m;
void add(int x,int p)
{
    for(int i=x;i<=n;i+=i&-i)
        num[i]+=p;
}

int query(int x)
{
    int ans=0;
    for(int i=x;i>=1;i-=i&-i){
        ans+=num[i];
    }
    return ans;
}


int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&q[i].l,&q[i].r);
    }
    sort(q+1,q+1+m);
    int ans=0;
    for(int i=1;i<=m;i++){
        int to = query(q[i].r)-query(q[i].l);
        if(to==0){
            add(q[i].r,1);
            ans++;
        }
    }
    printf("%d\n",ans);
    return 0;

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值