flandre
给定一个长度为
初始贡献为你选择的数之和。
设新的数列是长度为
当
当
当
求最大的贡献。
可以发现逆序对会造成负的贡献,所以选择的数一定是升序的。
如果不考虑重复元素,可以发现选择的数一定是一段完整的后缀(如果不是,可以恰好移到贴合)。
如果有重复元素,可以将相同的元素看作一个元素,如果某一段选择包含某个数,前面也可以选择,还可以使得
所以可以考虑利用桶排方便的统计后面的数的个数(对于所有数作
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N=1000010,M=2000010,B=1e6;
void read(int &x){
char c=getchar();
x=0;
bool f=0;
while(c<'0'||c>'9')f|=c=='-',c=getchar();
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
f&&(x=-x);
}
int n,k,c[M],id=-1,h[M],idx,e[M],ne[M],maxn,minn=1e9,id2;
typedef long long ll;
char num[30];
ll ans,now,res;
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void write(ll x,char fg=' '){
int cur=0;
while(x)num[cur++]=x%10+'0',x/=10;
while(cur--)putchar(num[cur]);
putchar(fg);
}
int main(){
memset(h,-1,sizeof h);
read(n),read(k);
for(int i=1;i<=n;++i){
int x;
read(x);
++c[x+B];
add(x+B,i);
maxn=max(maxn,x+B);
minn=min(minn,x+B);
}
for(int i=maxn;i>=minn;--i){
ans+=c[i]*(i-B)+now*c[i]*k;
now+=c[i];
if(ans>res){
id=i,id2=now;
res=ans;
}
}
if(id==-1){
puts("0 0");
return 0;
}
write(res),write(id2,'\n');
for(int j=id;j<M;++j)
for(int i=h[j];~i;i=ne[i])
write(e[i]);
return 0;
}
本文作者:wscqwq
本文链接:https://www.cnblogs.com/wscqwq/p/17768175.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步