HDU 2681 MM Programming Club(线段树维护||暴力贪心)

Problem Description

ACM is popular in HDU. Many girls want to learn more about programming skills in ACM. As one of assistances of Lcy, Yifenfei is now busy preparing a new club called “MM Programming Club”. Of Course, He will be the leader of the club, and teach these girls patiently. After the news posted around the campus, as many as N girls are determined to take part in the club. However, the numbers of members are limited; Yifenfei will only select K of them. It is quite a difficult problem. Here is a list of all information about N girls. Each of them has intelligence value and prettiness value. He also wants these K members such that the difference of intelligence between any two of them must not be greater than MAXK (If K = 1, the difference is zero). Now he wants to maximize the Sum of these K girls’ prettiness value.

Input

Many test case, please process to end of file. Each test first contains three integers N(1 <= N <= 200), K(1 <= K <= N), MAXK(1 <= MAXK <= 500). Then N lines follow. Each line contains two integers S, T (1 <= S, T <= 500). S represents the intelligence value, and T represents the prettiness value.

Output

If he can’t succeed in selecting K girls, print “-1”. Otherwise, Print the maximum the Sum of these K girls’ prettiness value.

Sample Input

2 1 0
1 2
2 3
2 2 0
1 2
2 3
2 2 1
1 2
2 3

Sample Output

3
-1
5

常规贪心思路:将所有人按智力排序,枚举每一个点作为最小的智力,可以取得一个智力差小于maxk的区间,然后在这个区间中取k个人,(把这个区间的人复制一份进行排序,取最大的k个人)

时间复杂度:第一层循环遍历(n)里面有两个小的循环(n)和一个sort (nlogn),整体的时间复杂度大概为n^2logn
#include <queue>
#include <cstdio>
#include<bits/stdc++.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#define  ll long long
using namespace std;
const int maxn=505;
const int inf=0x3f3f3f3f;
struct node
{
    int v,w;//智力,美貌
};
node w[maxn];
bool cmp1(node a,node b)//智力升序排列
{
    return a.v<b.v;
}
bool cmp2(int a,int b)//美貌降序排列
{
    return a>b;
}
int main()
{
    //freopen("text.txt","r",stdin);
    int n,k,maxk;
    while(~scanf("%d %d %d",&n,&k,&maxk))
    {
        for(int i=1; i<=n; ++i)
            scanf("%d %d",&w[i].v,&w[i].w);
        sort(w+1,w+n+1,cmp1);//智力升序排列
        int ans=-inf;
        for(int i=1; i<=n; ++i)
        {
            int b[505],b_t=0;
            for(int j=i;j<=n&&w[j].v-w[i].v<=maxk;++j)
                b[b_t++]=w[j].w;//将智力差小于maxk的人复制到数组b中
            if(b_t<k)//如果人数不够就不能选够人,跳出
                continue;
            sort(b,b+b_t,cmp2);//美貌降序排列
            int ne=0;
            for(int j=0;j<k;++j)//选美貌值最高的k个人
                ne+=b[j];
            ans=max(ans,ne);//每一次取最大值
        }
        if(ans!=-inf)
            printf("%d\n",ans);
        else
            printf("-1\n");
    }
    return 0;
}

线段树进行维护…取k个美貌最大的

时间复杂度:排序(nlogn)建树(log500),遍历点(n)每一次插值和删值(log500),大概有2n次,搜索log500,整体的时间复杂度大概为2nlog500
#include <queue>
#include <cstdio>
#include<bits/stdc++.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#define  ll long long
using namespace std;
const int maxn=505;
const int inf=0x3f3f3f3f;
struct node
{
    int l,r,num,v;//左右边界,包含的个数,美貌值
};
node w[maxn<<2];
struct nod
{
    int v,w;//智力,美貌
};
nod a[maxn];
bool cmp(nod a,nod b)//智力值升序排序
{
    return a.v<b.v;
}
void build(int e,int l,int r)
{
    w[e].l=l,w[e].r=r,w[e].num=0,w[e].v=0;
    if(l==r)
        return;
    int mid=(l+r)>>1;
    build(e<<1,l,mid);
    build(e<<1|1,mid+1,r);
}
void pushup(int e)//向上更新
{
    w[e].v=w[e<<1].v+w[e<<1|1].v;
}
void add(int e,int k)//添加一个美貌值为k的元素
{
    w[e].num++;
    if(w[e].l==w[e].r)
    {
        w[e].v+=k;
        return;
    }
    int mid=(w[e].l+w[e].r)>>1;
    if(k<=mid)
        add(e<<1,k);
    else
        add(e<<1|1,k);
    pushup(e);
}
void sub(int e,int k)//减去一个美貌值为k的元素
{
    w[e].num--;
    if(w[e].l==w[e].r)
    {
        w[e].v-=k;
        return;
    }
    int mid=(w[e].l+w[e].r)>>1;
    if(k<=mid)
        sub(e<<1,k);
    else
        sub(e<<1|1,k);
    pushup(e);
}
int query(int e,int k)//在节点e下找k个元素(最大的)
{
    if(w[e].l==w[e].r)
        return w[e].l*k;
    if(w[e<<1|1].num>k)//右子树元素大于k(建树叶子节点美貌值升序,右子树肯定优于左子树)
        return query(e<<1|1,k);//在右子树找
    else
        return query(e<<1,k-w[e<<1|1].num)+w[e<<1|1].v;
}
int main()
{
    //freopen("text.txt","r",stdin);
    int n,k,maxk;
    while(~scanf("%d %d %d",&n,&k,&maxk))
    {
        for(int i=1; i<=n; ++i)
            scanf("%d %d",&a[i].v,&a[i].w);
        sort(a+1,a+n+1,cmp);//智力值升序排序
        build(1,1,500);//建立一棵1-500的空树
        int j=1,ans=-inf;//所取长度为j-i
        for(int i=1; i<=n; ++i)//遍历
        {
            add(1,a[i].w);//将当前元素插入线段树
            while(j<=i&&a[i].v-a[j].v>maxk)//如果差值过大,每一次将智力最小的丢弃
            {
                sub(1,a[j].w);
                ++j;
            }
            if(i-j+1>=k)//如果区间j-i中人数大于等于k个,就在线段树中取美貌值前k个人
                ans=max(ans,query(1,k));//每一次取最大值
        }
        if(ans!=-inf)
        printf("%d\n",ans);
        else
            printf("-1\n");
    }
    return 0;
}
发布了145 篇原创文章 · 获赞 30 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_43984169/article/details/97907497
mm
今日推荐