[2023四校联考3]flandre
flandre
题目:
芙兰朵露有 nn 种烟花,每种都有两个参数:「真实效果」aa 和「感觉效果」bb,其中「真实效果」是一个给定不变的整数(可以为负),「感觉效果」初值等于「真实效果」。
将烟花按一定顺序燃放,先燃放的烟花会使得后面「真实效果」较差的烟花「感觉效果」更差,「真实效果」更优的「感觉效果」更优。
具体来说,对于所有 i<j,即烟花 i 在 j 前燃放,则有以下三种情况:
a_i < a_j 则 b_j <-- b_j+k
a_i = a_j 则 b_j不变
a_i > a_j 则 b_j <-- b_j-k
其中 k 为给定常数。
芙兰朵露想使「感觉效果」总和尽量大。也就是说,她想选一部分(可以全选或不选,不能重复选择)按一定顺序燃放,假设选了 m 个,使 ∑(i=1~m) b_i 最大。输出最大值及方案,有多解输出其一即可。
思路:
最先看样例,发现原数组所有数字均大于0,且它们在答案中均被使用,
并且排成了不下降序列。
所以我一开始认为,只要把所有数据排序,就能得到答案。
回忆:
1.接下来注意到ai有负数,如果在答案数列中加入负数,那么总答案会变小。我不想让这个负数减少总答案,
接着我认为这个负数可以由在数列中排在它前面的负数给它提供多个k的加成、使它变成非负数,那么排在前面的负数
也应该如此处理吧,但这样就会无限循环下去、变的无解。。。
2.Thinking...,让目光向前扫射,这个负数会对之后大于它的每个数有一个k的加成(k>0),如果这个负数 对之后数字的
总加成 + 自己(自己<0) < 0,那么这个数字要了会亏本、所以不能要。貌似所有的负数都可以这么处理。。。
3....不下降序列,...每个数对之后大于它的数有加成,...正数全要,
负数要考虑自己数值与带来的加成总值的绝对值大小,......
回到现实:
==> 对原数组排序,从大到小依次遍历,并统计每个数数值对答案的贡献总和(sum_all)和每个数对身后数字的加成之和(praise_all),
当某个数的数值+对身后数字的加成值<0时,我们就退出循环,输出答案。
1.排序后,将数组去重、并统计每个数字的副本数(我用sum[]存储二者)
2.solve1()用来处理 数据全为非负数的排序数组,solve2()则用来处理含有负数的排序数组
代码:
#include <iostream>
#include <algorithm>
#include <cstdio> //necessery
using namespace std;
#define ll long long
const int N=1e6+10;
int n;
ll k;
bool _minus=false;
struct number{
int id;
ll val;
}a[N];
struct ff{
int cnt;
ll val;
}sum[N]; int cnt1=0;
bool cmp(number x,number y) {
if(x.val!=y.val) return x.val<y.val;
return x.id<y.id;
}
void input() {
ll x;
for(int i=1;i<=n;i++) {
cin>>x;
if(x<0 && _minus==false) _minus=true;
a[i].id=i;
a[i].val=x;
}
}
void tongji() {
ll sta=a[1].val;
int s=1;
for(int i=2;i<=n;i++) {//统计数字副本数
if(a[i].val!=sta)
{
sum[++cnt1].cnt=s;
sum[cnt1].val=sta;
s=1;
sta=a[i].val;
}
else
{
s++;
}
}
sum[++cnt1].cnt=s;
sum[cnt1].val=sta;
}
void solve1() {
ll praise_all=0, num_all=0, ans=0;
int pre_sum=0;
for(int i=cnt1;i>=1;i--)
{
num_all+=(sum[i].cnt*sum[i].val);
praise_all+=(pre_sum*sum[i].cnt*k);
pre_sum+=sum[i].cnt;
}
ans=ans+num_all+praise_all;
cout<<ans<<' '<<n<<'\n';
for(int i=1;i<=n;i++) cout<<a[i].id<<' ';
}
void solve2() {
ll praise_all=0, num_all=0, ans=0;
int pre_sum=0;
for(int i=cnt1;i>=1;i--)
{
if(sum[i].val+pre_sum*k<0) { //不能要了
break;
}
num_all+=(sum[i].cnt*sum[i].val);
praise_all+=(pre_sum*sum[i].cnt*k);
pre_sum+=sum[i].cnt;
}
ans=ans+num_all+praise_all;
cout<<ans<<' '<<pre_sum<<'\n';
for(int i=n-pre_sum+1;i<=n;i++) cout<<a[i].id<<' ';
}
int main() {
// freopen("flandre.in","r",stdin);
// freopen("flandre.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>n>>k;
input();
sort(a+1,a+1+n,cmp);
tongji();
if(_minus==false) //没有负数
{
solve1();
}
else
{
solve2();
}
return 0;
}