我至今不敢相信我被这么一道简单的题卡了这么久……看来还是太弱了……
题目链接:CF原网
题目大意:定义一个序列的“美丽度”为这个序列前 $m$ 大的数的和。现在有一个长度为 $n$ 的序列,你需要把它分成 $k$ 个长度至少为 $m$ 的连续子序列,每个元素不重不漏,使得这些子串的“美丽度”之和最大。而且要求输出划分方案。
$1le nle 2 imes 10^5,mge 1,kge 2,m imes kle n$。
贪心地想,最后的划分方案中,计入总和的数,应该是原序列中前 $m imes k$ 大的数。如果有相同的数,随便选都行。
把这 $m imes k$ 个数标记一下。
那么究竟可不可以做到呢?其实很简单,从第一个还未被分配的数开始选,不断往后推,如果当前已经有了 $m$ 个数,那么这一段就是答案的一个子序列。
时间复杂度 $O(nlog 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 ",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++; } }