CSU 1554 SG Value 动态维护最小不可组成的数

题目链接:点击打开链接

题意:

n个操作

1 val 在集合中插入val

2 查询当前集合 通过任意数求和不能得到的最小正整数
思路:

空集合时ans=1

且插入数字后ans只能增加,所以维护这个ans

ans是 a1+a2+a3···+ai < ans < ai+1 的最小的i

所以ans是最小的前缀和+1且<ai+1

用multiset记录ai+1 ··an

插入的数<=ans时才会更新答案,所以复杂度是nlogn

----------------

证明:

首先我们设这个最小不能组成的数为ans,则空集合时ans = 1

而且随着数字的插入,ans是只增不减的。

假设当前我们不能组成的最小数字是ans,则[1,ans) 都是能组成的。

当我们插入一个数num 时:


假设插入前能组成的区间是 [0,ans)

增加num,这个区间偏移量就是num,能组成的区间=>[num, ans+num)

当且仅当[0,ans) 和 [num, ans+num) 能拼接时,答案才会增加 => 当num<=ans 时答案才会增加。

则答案会更新为新区间的右端点=>ans = ans+num;

若不能拼接,则不会增加答案,所以就把这个数存起来。

每次更新完答案,我们把存起来的数中最小的拿出来,看一下能否再次更新答案,直到最小的数也不能更新答案为止。


#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <map>
#include <cmath>
#include <set>
template <class T>
inline bool rd(T &ret) {
	char c; int sgn;
	if(c=getchar(),c==EOF) return 0;
	while(c!='-'&&(c<'0'||c>'9')) c=getchar();
	sgn=(c=='-')?-1:1;
	ret=(c=='-')?0:(c-'0');
	while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
	ret*=sgn;
	return 1;
}
template <class T>
inline void pt(T x) {
    if (x <0) {
        putchar('-');
        x = -x;
    }
    if(x>9) pt(x/10);
    putchar(x%10+'0');
}
using namespace std;
typedef long long ll;


int n;
ll ans;
multiset<ll>s;
multiset<ll>::iterator it;

int main() {
    while(cin>>n){
    	s.clear();
    	int op; ll val;
    	ans = 1;
		while(n-->0){
			rd(op);
			if(op == 2) pt(ans), putchar('\n');
			else {
				rd(val);
				if(val <= ans){
					ans += val;
					while((int)s.size()){
						it = s.begin();
						if(ans>=(*it))
						{
							ans += *it;
							s.erase(it);
						}
						else break;
					}
				}
				else	s.insert(val);
			}
		}
    }
    return 0;
}
/*
99
2
1 3
2
1 2
2
1 1
2
1 7
2


99
2
1 1
2
1 2
2
1 4
2
1 7
2


*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值