CF1114B Yet Another Array Partitioning Task(贪心,构造题)

我至今不敢相信我被这么一道简单的题卡了这么久……看来还是太弱了……

题目链接:CF原网

题目大意:定义一个序列的“美丽度”为这个序列前 $m$ 大的数的和。现在有一个长度为 $n$ 的序列,你需要把它分成 $k$ 个长度至少为 $m$ 的连续子序列,每个元素不重不漏,使得这些子串的“美丽度”之和最大。而且要求输出划分方案。

$1\le n\le 2\times 10^5,m\ge 1,k\ge 2,m\times k\le n$。


贪心地想,最后的划分方案中,计入总和的数,应该是原序列中前 $m\times k$ 大的数。如果有相同的数,随便选都行。

把这 $m\times k$ 个数标记一下。

那么究竟可不可以做到呢?其实很简单,从第一个还未被分配的数开始选,不断往后推,如果当前已经有了 $m$ 个数,那么这一段就是答案的一个子序列。

时间复杂度 $O(n\log n)$。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn=200020;
#define MP make_pair
#define PB push_back
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline int read(){
    char ch=getchar();int x=0,f=0;
    while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return f?-x:x;
}
int n,m,k;
bool tag[maxn];
ll ans;
struct node{
    int val,id;
    bool operator<(const node &nd)const{
        if(val!=nd.val) return val>nd.val;
        return id<nd.id;
    }
}nd[maxn];
int main(){
    n=read();m=read();k=read();
    FOR(i,1,n) nd[i].val=read(),nd[i].id=i;
    sort(nd+1,nd+n+1);
    FOR(i,1,m*k) ans+=nd[i].val,tag[nd[i].id]=true;    //累加答案,标记
    printf("%lld\n",ans);
    int tot=1;
    FOR(i,1,n){
        int cnt=0,j=i;    //从还未分配的开始
        while(j<=n && cnt<m){    //还不足m个
            if(tag[j]) cnt++;
            j++;
        }
        i=j-1;    //注意-1
        if(tot<k) printf("%d ",i),tot++;
    }
}
View Code

猜你喜欢

转载自www.cnblogs.com/1000Suns/p/10361982.html
今日推荐