闲话 10.30
别样的丁真让我讲 T2,所以提前写点东西出来。
诗人小G
首先根据题意,比较好写的是 \(\mathcal{O(n^2)}\) 的转移:
\[f_i=\min_{j=0}^{i-1}\ f_{j}+abs(sum_i-sum_j-L-1)^p
\]
其中 \(sum\) 为句子长度的前缀和。
发现可优化的点是后面一坨柿子,我们把它记为 \(G_{i,j}=abs(sum_i-sum_j-L-1)^p\)。如果它具有决策单调性,那么我们就可以上单调队列优化了。
只需证明 $G_{i+1,j}+G_{i,j+1}\ge G_{i,j}+G_{i+1,j+1} $,即 \(G_{i,j}\) 满足四边形不等式。做法是拆开移项合并再分讨,搬锣鼓题解了。
然后直接上单调队列即可。
需要注意的是本题有很多细节问题,行中有空格行尾每空格,办法可以是在求前缀和前直接处理好,当然也可以中途处理,就是有点麻烦。以及数据范围,题目贴心地提示了可能会出现状态的值 \(\gt 10^{18}\) 的情况,我们可以以精度换值域使用 long double
存储,然后就做完了。复杂度 \(\mathcal{O(Tn\log n))}\)。
P1204 [USACO1.2] 挤牛奶Milking Cows
唐题,看到线段树就进去做了,然后被橙题硬控。
发现是一个简单版(?)山海经,我们记录最长的连续挤奶/不挤奶时间,包含左/右端点的连续挤奶/不挤奶时间,并记录该段是否整段挤奶/不挤奶。
需要注意的是题目的问题是基于段的,段权值转点权值直接左闭右开处理。还有就是注意线段树维护的范围是固定的,读入时处理一下即可。
点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(register int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(register int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{
char ch = getchar(); lx x = 0, f = 1;
for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ 48);
return x * f;
}
#undef lx
#define qr qr()
#define fi first
#define se second
#define pii pair<int, int>
#define P_B(x) push_back(x)
#define M_P(x, y) make_pair(x, y)
const int Ratio = 0;
const int N = 1e6 + 5;
const int mod = 1e9 + 7;
int m, n, st = 1e9;
pii zc[N];
int ma[N << 2][2], llen[N << 2][2], rlen[N << 2][2];
bool man[N << 2][2];
namespace Wisadel
{
#define ls (rt << 1)
#define rs (rt << 1 | 1)
#define mid ((l + r) >> 1)
void Wpushup(int rt)
{
ma[rt][1] = max(ma[ls][1], ma[rs][1]);
ma[rt][0] = max(ma[ls][0], ma[rs][0]);
llen[rt][1] = llen[ls][1] + (man[ls][1] ? llen[rs][1] : 0),
llen[rt][0] = llen[ls][0] + (man[ls][0] ? llen[rs][0] : 0);
rlen[rt][1] = rlen[rs][1] + (man[rs][1] ? rlen[ls][1] : 0),
rlen[rt][0] = rlen[rs][0] + (man[rs][0] ? rlen[ls][0] : 0);
ma[rt][1] = max(ma[rt][1], rlen[ls][1] + llen[rs][1]);
ma[rt][0] = max(ma[rt][0], rlen[ls][0] + llen[rs][0]);
man[rt][1] = (man[ls][1] && man[rs][1]);
man[rt][0] = (man[ls][0] && man[rs][0]);
}
void Wbuild(int rt, int l, int r)
{
if(l == r)
{
ma[rt][1] = llen[rt][1] = rlen[rt][1] = 0;
ma[rt][0] = llen[rt][0] = rlen[rt][0] = 1;
man[rt][0] = 1, man[rt][1] = 0;
return ;
}
Wbuild(ls, l, mid), Wbuild(rs, mid + 1, r);
Wpushup(rt);
}
void Wupd(int rt, int l, int r, int x, int y)
{
if(man[rt][1]) return ;
if(x <= l && r <= y)
{
ma[rt][1] = llen[rt][1] = rlen[rt][1] = r - l + 1;
ma[rt][0] = llen[rt][0] = rlen[rt][0] = 0;
man[rt][1] = 1, man[rt][0] = 0;
return ;
}
if(x <= mid) Wupd(ls, l, mid, x, y);
if(y > mid) Wupd(rs, mid + 1, r, x, y);
Wpushup(rt);
}
short main()
{
// freopen(".in", "r", stdin), freopen(".out", "w", stdout);
m = qr;
fo(i, 1, m) zc[i].fi = qr, zc[i].se = qr - 1, n = max(n, zc[i].se), st = min(st, zc[i].fi);
Wbuild(1, st, n);
fo(i, 1, m) Wupd(1, st, n, zc[i].fi, zc[i].se);
printf("%d %d\n", ma[1][1], ma[1][0]);
return Ratio;
}
}
signed main(){return Wisadel::main();}