CF-1028D Order book

订单簿() --CF-1028D --2100

时间限制:\(2000ms\) 空间限制:\(256MB\)

题目描述:

存在两个集合 \(A,B\),集合 \(A\) 可以每次取出集合中的最大值,集合 \(B\) 可以每次取出集合中的最小值。

有两种操作,都有给定参数 \(x\)

  • ADD :往某一个集合中插入 \(x\)
  • ACCEPT:从某一个集合中取出对应的值,且这个值为 \(x\)

存在 \(n\) 次操作,每次给定操作类型和 \(x\)

请有多少种合法的选择(即每一次操作选择哪个集合),可以使得整个操作序列合法。

若无解则输出 \(0\),保证所有给定的 \(x\) 互不相同。

输入描述:

第一行包含一个整数 \(n\) (\(1 \le n \le 363\,304\)) ,表示操作数。

接下来的 \(n\) 行中,每行包含一个字符串 ACCEPT 或者 ADD,以及一个整数 \(x\) (\(1 \le x \le 308\,983\,066\))。

输出描述:

能使所有操作都合法的方案数,答案对 \(10^9 + 7\) 取模。

样例输入输出:

输入1 输出1 输入2 输出2 输入3 输出3
6
ADD 1
ACCEPT 1
ADD 2
ACCEPT 2
ADD 3
ACCEPT 3
8
4
ADD 1
ADD 2
ADD 3
ACCEPT 2
2
7
ADD 1
ADD 2
ADD 3
ADD 4
ADD 5
ACCEPT 3
ACCEPT 5
0

样例解释:

在第一个例子中,每个元素都可以放入任意集合。

在第二个例子中,元素 \(1\) 必须放入集合 \(A\),元素 \(3\) 必须放入集合 \(B\).

思路

考虑维护 \(l,r\) 分别表示 \(A\) 集合合法最大值的最小值、\(B\) 集合合法最小值的最大值,规定 \(l\) 插入了 \(A\)\(r\) 插入了 \(B\)

对于插入操作:

  • 如果插入的数在 \(l\) 左侧或 \(r\) 右侧,则这个数所在集合是确定的;
  • 否则这个数可能存在于两种集合。

对于取出操作:

  • 如果取出的数在 \(l\) 左侧或 \(r\) 右侧,说明取出的数无法成为集合中的极值,可以判断无解;
  • 否则,若 \(x\neq l\)\(x\neq r\),说明 \(x\) 可以放入两个集合,答案翻倍;
  • 如果 \(x=l\)\(x=r\),直接取出即可。

每次取出后需要维护 \(l,r\),将 \(l\) 变为最大的小于 \(x\) 的数,将 \(r\) 变为最小的大于 \(x\) 的数。

更新 \(l,r\) 可以通过 set 维护。

同时,需要记录当前 \((l,r)\) 内待确定的数量。如果最终有 \(cnt\) 个数没有确定集合,那么答案需要乘上 \(cnt+1\),因为你可以在 \(cnt+1\) 个位置划分,将他们分别插入两个集合。

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
int n,l,r;
set<int>s;
int cnt,ans;
signed main()
{
	cin>>n; ans=1;
	l=-1e9,r=1e9;
	s.insert(l);
	s.insert(r);
	while(n--)
	{
		string opt;
		int x;
		cin>>opt>>x;
		if(opt=="ADD")
		{
			s.insert(x);
			if(x>l && x<r) cnt++;
		}
		else
		{
			cnt=0;
			if(x<l || x>r)
			{
				cout<<0<<endl;
				return 0;
			}
			if(x>l && x<r) ans=ans*2%mod;
			auto it=s.find(x);
			it--; l=*it;
			it++; it++;
			r=*it; it--;
			s.erase(it);
		}
	}
	ans=ans*(cnt+1)%mod;
	cout<<ans<<endl;
	return 0;
}
posted @ 2025-07-22 14:10  crazy--boy  阅读(10)  评论(0)    收藏  举报