闲话 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}\) 满足四边形不等式。做法是拆开移项合并再分讨,搬锣鼓题解了。

image
image

然后直接上单调队列即可。

需要注意的是本题有很多细节问题,行中有空格行尾每空格,办法可以是在求前缀和前直接处理好,当然也可以中途处理,就是有点麻烦。以及数据范围,题目贴心地提示了可能会出现状态的值 \(\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();}

完结撒花~

image

posted @ 2024-10-30 17:56  Ratio_Y  阅读(64)  评论(6编辑  收藏  举报