P10083 [GDKOI2024 提高组] 不休陀螺 题解

显然我们要解决的主要问题就是能“陀螺无限”的充要条件。我们坚信推出来后是可以维护的。

我们设我们要打出的这些牌的 a,ba,b 分别是 a1,a2,,aka_1,a_2,\cdots,a_kb1,b2,,bkb_1,b_2,\cdots,b_k

容易观察到一个必要条件是 i=1kbiai0\sum \limits_{i=1}^k b_i-a_i \geq 0,否则每打完一次能量总是降低,最终一定无法无限打下去。

但是这个条件不充分。反方向考虑什么时候打不完。如果存在一种方法使得无法无限打,那么一定是在第一局。因为在后面的局数中,能量总是不小于第一局的初始值,故不优。

那么如果存在 aabb 的一种排列,使得存在 iiE+j=1i1bjaj<aiE+\sum \limits_{j=1}^{i-1} b_j-a_j < a_i,就无法无限打下去。此时无法打出第 ii 张牌。

这时考虑反方,即不想让你打完的会怎么想。肯定是把 bi<aib_i< a_i 的全都放在前面,然后放某个 aa。记 p=i=1kmax{0,aibi}p = \sum \limits_{i=1}^k \max\{0,a_i-b_i\}

考虑任意一个 ii,如果 aibia_i \leq b_i,那么这张牌没有被选过,此时需要判断 EpE - paia_i 的关系。移项得 EEai+pa_i +p 的关系。

如果 ai>bia_i > b_i,那么此时需要判断 Ep+aibiE-p+a_i-b_iaia_i 的关系。移项得 EEbi+pb_i+p 的关系。

发现 aibia_i \leq b_i 时是 ai+pa_i + pai>bia_i > b_i 时是 bi+pb_i+p。所以是 min{ai,bi}+p\min\{a_i,b_i\}+p

能无限打的充要条件是 bab-a 的和大于等于 00,且对于任意 ii,有 Emin{ai,bi}+pE\geq\min\{a_i,b_i\}+p 成立。

第一个条件不太好处理,先考虑第二个,一定是 Emaxi=1k(min{ai,bi})+pE \geq \max \limits_{i=1}^k (\min\{a_i,b_i\})+p 成立。

如果枚举左端点 ll,二分 rrpp 随着 rr 增大而单调不降,maxi=1k(min{ai,bi})\max \limits_{i=1}^k (\min\{a_i,b_i\}) 显然也是单调不降。所以右边式子有单调性,可以二分右端点求出每个 ll 对应的最大的 rr。可以用 ST 表和前缀和处理这一部分。

但是还有一点在于上文提到的难以维护的限制,即 biaib_i-a_i 的和大于等于 00。如果使用前缀和 sumbi=j=1ibj,sumai=j=1iajsumb_i = \sum \limits_{j=1}^i b_j,suma_i = \sum \limits_{j=1}^i a_j。那么上面的限制等价于 sumbrsumbl1sumarsumal1sumb_r-sumb_{l-1} \geq suma_r-suma_{l-1}。注意到枚举左端点时,sumal1suma_{l-1}sumbl1sumb_{l-1} 是定值,进行上文的二分右端点后问题转化成区间 [l,r][l,r] 中的 sumbrsumarsumb_r-suma_r 大于等于一个定值的问题。这是一个二维偏序,显然可以离线树状数组或者在线主席树维护。

于是问题在 O(nlogn)O(n \log n) 的时空复杂度内得以解决。

主席树代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 1e6 + 5;

int a[N], b[N];
long long sumc[N];
int n;
long long e;
int f[N][22], LG2[N];

void Init()
{
	for (int i = 2; i < N; i++) LG2[i] = LG2[i >> 1] + 1;
	for (int i = 1; i <= n; i++) f[i][0] = min(a[i], b[i]);
	for (int j = 1; j <= LG2[n]; j++)
	{
		for (int i = 1; i + (1 << j) - 1 <= n; i++)
		{
			f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
		}
	}
}

int query(int l, int r)
{
	int p = LG2[r - l + 1];
	return max(f[l][p], f[r - (1 << p) + 1][p]);
}

int rt[N];

class Chariman_Tree
{
public:
	int idx;
	struct Node
	{
		int lson, rson, sum;
	}tr[N * 26];
	void pushup(int u)
	{
		tr[u].sum = tr[tr[u].lson].sum + tr[tr[u].rson].sum;
	}
	int ins(int p, int u, int v, int l, int r)
	{
		u = ++idx;
		tr[u] = tr[p];
		if (l == r)
		{
			tr[u].sum++;
			return u;
		}
		int mid = (l + r) >> 1;
		if (v <= mid) tr[u].lson = ins(tr[p].lson, tr[u].lson, v, l, mid);
		else tr[u].rson = ins(tr[p].rson, tr[u].rson, v, mid + 1, r);
		pushup(u);
		return u;
	}
	int query(int p, int q, int l, int r, int nl, int nr)
	{
		if (!p && !q) return 0;
		if (l >= nl && r <= nr) return tr[q].sum - tr[p].sum;
		int mid = (l + r) >> 1;
		int ans = 0;
		if (nl <= mid) ans = query(tr[p].lson, tr[q].lson, l, mid, nl, nr);
		if (nr > mid) ans += query(tr[p].rson, tr[q].rson, mid + 1, r, nl, nr);
		return ans;
	}
}sgt;

long long sumd[N];

int main()
{
	ios::sync_with_stdio(0), cin.tie(0);
	cin >> n >> e;
	long long ans = 0LL;
	for (int i = 1; i <= n; i++) cin >> a[i];
	vector<long long> vv;
	for (int i = 1; i <= n; i++) 
	{
		cin >> b[i];
		sumc[i] = sumc[i - 1] + max(0LL, (long long)a[i] - b[i]);
		sumd[i] = sumd[i - 1] + b[i] - a[i];
		vv.emplace_back(sumd[i]);
	}
	vv.emplace_back(0);
	sort(vv.begin(), vv.end());
	vv.erase(unique(vv.begin(), vv.end()), vv.end());
	for (int i = 0; i <= n; i++) sumd[i] = lower_bound(vv.begin(), vv.end(), sumd[i]) - vv.begin() + 1;
	for (int i = 0; i <= n; i++) 
	{
		rt[i] = sgt.ins((i ? rt[i - 1] : 0), rt[i], sumd[i], 1, n + 1);
	}
	Init();
	for (int i = 1; i <= n; i++)
	{
		int l = i, r = n, place = -1;
		while (l <= r)
		{
			int mid = (l + r) >> 1;
			long long g = e - (sumc[mid] - sumc[i - 1]);
			if (query(i, mid) <= g) l = mid + 1, place = mid;
			else r = mid - 1;
		}
		if (place != -1) ans += sgt.query(rt[i - 1], rt[place], 1, n + 1, sumd[i - 1], n + 1);
		//cout << i << " " << place << "\n";
	}
	//cout << (double)(&st - &ed) / 1024.0 / 1024.0 << "\n";
	cout << ans << "\n";
	return 0;
}
posted @   HappyBobb  阅读(26)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示