首页 > 其他分享 >[2023四校联考3]flandre

[2023四校联考3]flandre

时间:2024-11-03 20:46:56浏览次数:1  
标签:效果 val int flandre sum 加成 负数 四校 联考

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;
}

标签:效果,val,int,flandre,sum,加成,负数,四校,联考
From: https://www.cnblogs.com/UeesugiSakura/p/18523946

相关文章

  • 洛谷 P6628 [省选联考 2020 B 卷] 丁香之路 做题记录
    图论好题啊!首先我们枚举终点\(u\),看到一定要走完指定的\(m\)条边,很像一条欧拉路问题啊!但是现在问题是一个欧拉路问题,有两个点的度数是奇数,并不好做。我们不妨先从起点\(s\)向\(u\)连一条边,变成欧拉回路问题。现在我们需要做的是将度数为奇数的点加边使其变为偶数。方法是......
  • 【省选联考2024】季风
    题面题目描述给定\(n,k,x,y\)和\(2n\)个整数\(x_0,y_0,x_1,y_1,\dots,x_{n-1},y_{n-1}\)。找到最小的非负整数\(m\),使得存在\(2m\)个实数\(x_0',y_0',x_1',y_1',\dots,x_{m-1}',y_{m-1}'\)满足以下条件,或报告不存在这样的\(m\):\(\sum\limits_{i=0}^{......
  • [技巧] 联考策略 2024.10.22
    (2024.10.22;我目前的水平)题目难度&我目前的水平T1:应当较快地做出来。但我目前很可能会在T1上花非常多时间(2h;最近两场考试);甚至做不出T1。T2:应当做出来。思维难度也许比T1低(最近两场考试),但可能还是T1要简单一些(毕竟[机房里T1得分比T2高些](?))。T3:可以尝试写部分分&......
  • 10.18noip联考总结
    10.18noip联考总结T1数据造的很水,按道理来说,std的\(O(64\timesn\times\log_2n)\)的做法是不能过掉极限数据的,可以进行特殊构造把std卡掉。在考场上也想到了与std相同复杂度的做法,但是在算了之后发现是不能过的,期望分数与暴力相同,所以也就没打,后面写了一个很假的做法......
  • 10.17noip联考总结
    10.17noip联考总结今天的命题人是xde……T1最后大约两个小时的时候想到了正解,但是在处理边界的时候出了问题,大样例一直过不了。其实只需要把数值统计下来再计算就行了。T2其实我们把给定的数给二进制拆开,就会发现其实就是对数进行调整把0调整为1。根据这个思路可以构造出一......
  • noip多校联考总结
    noip多校联考总结10.14T1不知道考场在干嘛,打了一个暴力,用了卡时,但是卡时在不同系统下单位不同,还好评测时环境与我本机的相同,clock函数都是以毫秒为单位的,谨记以后要写if(clock()/CLOCKS_PER_SEC>=0.95)break;而不是类似于if(clock()>=950)break;,纯属运气比较好,要是在正式考......
  • 洛谷题单指南-字符串-P5283 [十二省联考 2019] 异或粽子
    原题链接:https://www.luogu.com.cn/problem/P5283题意解读:n个整数,每次从从取l~r的数进行异或得到美味值,一共取k次,并计算这k个美味值之和的最大值。解题思路:1、如何O(1)的计算l~r数的异或,得到美味值可以借助前缀和思想,a[i]为第i个数,s[i]表示a[1]~a[i]每个数的异或值,要计算l~r的......
  • 10.11日noip多校联考总结
    10.11日noip多校联考总结T1看到感觉像是一个很玄学的题目,在考场上推了大概一个多小时,又写了大概半个小时,终于调出来了。谨记:三分取mid需要进行浮点数运算。对于每一行和每一列定义两个数组来记录要加多少,因为我们只需要知道其中任意一个数就可以推出所有的数,那么考虑枚举x0,来......
  • 10.10日noip多校联考总结
    10.10日noip多校联考总结T1感觉就是个dij再多记录一个换乘次数然后就像普通dij一样跑就行了。但是必须得将换乘次数放进dis数组中当成一个状态记录下来,不能只记录在堆中,不然做法会假。T2发现m=0的部分分就是用一个数据结构维护区间最大子段和。m=1/2就是同时维护一个最大值......
  • 洛谷 P7517 [省选联考 2021 B 卷] 数对
    题目传送门解题思路其实你只要知道:这题你就秒了。我们发现 ,于是开一个桶来统计每个数出现的数量。我们只需要枚举每一个数的倍数,然后统计。最后,如果一个数出现了多次,再特判一下即可。代码#include<bits/stdc++.h>usingnamespacestd;intn;intcnt[500001];......