P10083 [GDKOI2024 提高组] 不休陀螺 题解
显然我们要解决的主要问题就是能“陀螺无限”的充要条件。我们坚信推出来后是可以维护的。
我们设我们要打出的这些牌的
容易观察到一个必要条件是
但是这个条件不充分。反方向考虑什么时候打不完。如果存在一种方法使得无法无限打,那么一定是在第一局。因为在后面的局数中,能量总是不小于第一局的初始值,故不优。
那么如果存在
这时考虑反方,即不想让你打完的会怎么想。肯定是把
考虑任意一个
如果
发现
能无限打的充要条件是
第一个条件不太好处理,先考虑第二个,一定是
如果枚举左端点
但是还有一点在于上文提到的难以维护的限制,即
于是问题在
主席树代码:
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现