首页 > 其他分享 >【luogu CF1098D】Eels(结论)

【luogu CF1098D】Eels(结论)

时间:2023-03-01 19:11:06浏览次数:57  
标签:Eels int luogu sum 2x 每次 贡献 CF1098D leqslant

Eels

题目链接:luogu CF1098D

题目大意

有一个可重集,每次操作会放进去一个数或者取出一个数。
然后每次操作完之后,问你对这个集合进行操作,每次选出两个数 a,b 加起来合并回去,直到集合中只剩一个数,要你最小化 2a<b 或 2b<a 的次数。
每次输出这个最小次数。

思路

有一个简单的贪心结论是每次选最小的两个合并。
感性理解就是你如果要贡献了,那迟早都要贡献,你这里加了说不定他就够大了就不一定在下一次贡献了。

接下来发现你这样这题好像还不能过。
于是考虑再推一点结论,发现它贡献的条件我们还没有用上。
于是考虑一下这个二倍,会发现一个什么问题,就是如果你某一次要贡献。
比如贡献的形式是 \(x,y\),其中 \(2x<y\),那你其实会发现这个 \(y\) 是不可能是被合并出来的,它一定是原生的。

那如果它能被合出来 \(y_1+y_2=y(y_1\leqslant y_2)\),那我们每次合最小的两个,那 \(y_1,y_2\) 已经被合了 \(x\) 还在,那一定有 \(y_1\leqslant y_2\leqslant x\),那 \(y_1+y_2\leqslant 2x\) 即 \(y\leqslant 2x\) 与 \(y>2x\) 矛盾。
也不难看出,当 \(kx<y\) 为条件的时候,两个推出来的条件分别是 \(y\leqslant 2x\) 与 \(y>kx\),也就是当 \(k\geqslant 2\) 的时候其实这个结论都成立,这也是这个条件成立的充要条件。

那这个说明什么,你如果要出现贡献,大的一定是原生的,而每次你都会合最小的两个,那要让大的是原生的也就是它是现在第二小的,而且比它大的里面不应该有非原生的。
因为有的话,就说明它肯定没有最小的二倍。
那最小的肯定就是原生的里面比他小的和。
那条件就是:(先把数组排序,在让 \(sum_i=\sum\limits_{x=1}^ia_x\))
\(\sum\limits_{i=1}^n[2sum_{i-1}<a_i]\)


那我们要做的就是在插入数和删去数的过程中维护这个东西的值。
会发现问题在于每个地方都要判断一次,但是一个显然的事情是每一次是上次的两倍以上,那每次这个值都会翻倍,那就只会有至多 \(\log\) 次贡献。
那你会发现如果你按最高位的存在来分(我们对于每个维护一个 set),那你会发现每一组至多只有一个贡献,那我们需要判断的次数也缩小到了 \(\log\) 级别,就可以了。

代码

#include<set>
#include<cstdio>
#define ll long long

using namespace std;

int n, ans;
multiset <int> s[36];
ll sum[36];

int getk(int x) {
	int re = 0;
	while (x > 1) re++, x >>= 1;
	return re;
}

int main() {
	scanf("%d", &n);
	while (n--) {
		char c = getchar(); while (c != '+' && c != '-') c = getchar();
		int x; scanf("%d", &x);
		int k = getk(x);
		if (c == '-') {
			s[k].erase(s[k].find(x));
			sum[k] -= x;
		}
		if (c == '+') {
			s[k].insert(x);
			sum[k] += x;
		}
		ll Sum = 0; ans = 0;
		for (int i = 0; i <= 30; i++)
			if (s[i].size()) {
				ans += s[i].size();
				if ((*s[i].begin()) > 2 * Sum) ans--;
				Sum += sum[i];
			}
		printf("%d\n", ans);
	} 
	
	return 0;
} 

标签:Eels,int,luogu,sum,2x,每次,贡献,CF1098D,leqslant
From: https://www.cnblogs.com/Sakura-TJH/p/luogu_CF1098D.html

相关文章

  • luogu P8444 不等价交换法则
    题目传送门分析仔细审了题面,猜想是贪心模拟,下面给出证明:因为只能用元买一个商品,所以要挑贵的买(越贵,换得的商品越多),后令商品尽可能的去换低价格的商品,即把手头所有的商品......
  • [luogu P4705玩游戏] 题解
    P4705玩游戏题解题意概括给出两个序列\(a_0,a_2,\cdotsa_{n-1}\),\(b_0,b_2,\cdotsb_{m-1}\),从两个序列中各等概率的选出两个数\(a_i,b_j\),对于\(k\in[1,t]\)......
  • Solution Luogu6097 子集卷积
    其实是暴力。因为这是模板题,所以模板的前置知识也要讲。前置知识:FWT计算或卷积。这里只需要掌握快速计算或卷积的方法,所以内容较少。如果向了解更多(比如异或卷积)的话......
  • LuoguP5354 [Ynoi2017]由乃的OJ题解
    P5354[Ynoi2017]由乃的OJPreface自己的由乃题一血,写篇题解纪念一下。Description给定一颗\(n\)个结点的树,每个结点都有一个权值\(a_i\)和一个位运算符\(\mathrm{......
  • 【题解】Luogu P3939 数颜色
    题目分析:解法一:显然我们可以直接对每一种颜色建一棵线段树,然后剩下的操作就非常简单了。代码:点击查看代码#include<bits/stdc++.h>usingnamespacestd;constint......
  • luogu7764[COCI2016-2017#5] Poklon
    luogu7764[COCI2016-2017#5]Poklonlink莫队解法看了题面之后,便知道能用莫队做。我们知道数组中的数据范围是小于\(10^{9}\)的自然数,而\(1\leN,Q\le5\times10......
  • 【NOIP2001】【Luogu1026】统计单词个数
    problemsolutioncodes//justfortest2#include<iostream>#include<algorithm>#include<cstring>#include<string>usingnamespacestd;intn,m,x,d[210],f......
  • 【NOIP2015】【Luogu2678】跳石头
    problemsolutioncodes//二分答案//QAQ注意:起点和终点也是有石头的w#include<iostream>#include<algorithm>#definemaxn100010usingnamespacestd;intll,n,......
  • 【NOIP2008】【Luogu1125】笨小猴
    problemsolutioncodes#include<iostream>#include<algorithm>#include<string>usingnamespacestd;inta[30];intmain(){stringstr;cin>>str;for......
  • 【Luogu3371】【模板】单源最短路径(SPFA)
    problem给出一个有向图求从某一点出发到所有点的最短路solutionSPFAcodes#include<iostream>#include<queue>#include<cstring>#definemaxn10010#definem......