qwq

ABC346题解(F&G)

\(a[l:r]\) 表示 \(a\) 这个 字符串/数组 的第 \(l\) 到第 \(r\) 个元素组成的 字符串/数组。类似的:link

F

考虑令 \(k=k0\),如何判断是否可行。

只需要对 \(T\) 从前到后一个一个字符满足,若无法满足则不可行。

具体的,即假设现在判断字符 \(c\),从第 \(q\) 次循环的字符串 \(S\) 的第 \(p\) 位开始。

令还需要在 \(S\) 中找到 \(c\) 的个数为 \(b\)\(cnt_c\ s\) 表示 \(s\)\(c\) 的个数。

如果 \(b > cnt_c\ s\),那么一直向后跳跃一整个字符串(即 \(q\gets q + 1\)),将 \(b\) 减去 \(cnt_c\ s\)

考虑如果可以在 \(s[p:|S|]\) 这个字符串里满足,那么直接将 \(p\) 跳跃到某个 \(c\) 的下一个位置 \(p'\),满足 \(cnt_c\ s[p:p']=b\) 即可。

否则令 \(b\gets b-cnt_c\ s[p:|S|]\),再令 \(q\gets q+1,p\gets 1\)

\(pos_c\ x\) 表示满足 \(cnt_c\ s[1:i]=x\) 的最小的 \(i\)

\(p\gets (pos_c\ b)+1\) 即可。

若最后 \(q>n\),则不可行。

注意到答案显然单调,二分答案即可。复杂度 \(O(|S|+|T|\log n)\)

G

看错题卡了好久。注意是至少有一个满足只出现一次而不是 恰好 有一个数只出现一次。

考虑从右向左扫描,若扫到 \(i\)

\(a[i:n]\)\(x\)\(i\) 次出现的位置为 \(pi_x\)

\(a[i:n]\) 可表示为 \(p1_{a_i},p1_{a_{i+1}},p2_{a_i}\cdots\)(只是一个例子)。

若将 \(p1_x\) 替换为 \(+1\)\(p2_x\) 替换为 \(-1\),其他为 \(0\),则 \(a[i:n]\) 变为 \(+1\ +1\ -1\ 0\cdots\)(只是一个例子)。

举例:若 \(a[i:n]=\{1,2,3,2,3,4,1,1\}\)

第一次用 \(pi_x\) 替换为 \(\{p1_1,p1_2,p1_3,p2_2,p2_3,p1_4,p2_1,p3_1\}\)

接下来变为 \(\{+1,+1,+1,-1,-1,+1,-1,0\}\)

注意到做一个前缀和后对于任意的 \(a[i:n]\) 没有数 \(<0\),并且不为 \(0\) 的数的个数即为 \(L=i\)\(R\) 的方案数,考虑维护做前缀和后的数列。

考虑类似于扫描线的方法,用线段树维护区间最小值和最小值的个数,因为最小值 \(\ge 0\)(和扫描线类似),所以方便统计。

每次向左加一个数时只需要考虑 \(pi_x\) 的变化并且区间修改前缀和就行了。复杂度 \(O(n\log n)\)

代码

F

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

#define int ll

const int N = 1e5 + 5, K = 26;

char s[N], t[N]; int n, sn, st;
int pos[N][K], suf[N][K], pre[N][K];
int cnt[26];

bool chk(int k)
{
    int p = 1, q = 1;
    for(int i = 1; i <= st; i ++)
    {
        int c = t[i] - 'a';
        if(!cnt[c]) return false;
        int k0 = k;
        if(k0 > cnt[c])
            q += (k0 - 1) / cnt[c], k0 = k0 - (k0 - 1) / cnt[c] * cnt[c];
        if(suf[p][c] < k0) k0 -= suf[p][c], p = 1, q ++;
        p = pos[pre[p - 1][c] + k0][c] + 1;
        if(p > sn) p = 1, q ++;
    }
    if(p == 1) q --;
    return q <= n;
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    cin >> n >> s + 1 >> t + 1;
    sn = strlen(s + 1);
    st = strlen(t + 1);
    for(int i = sn; i >= 1; i --)
    {
        cnt[s[i] - 'a'] ++;
        for(int j = 0; j < K; j ++) suf[i][j] = cnt[j];
    }
    memset(cnt, 0, sizeof cnt);
    for(int i = 1; i <= sn; i ++)
    {
        cnt[s[i] - 'a'] ++;
        pos[cnt[s[i] - 'a']][s[i] - 'a'] = i;
        for(int j = 0; j < K; j ++) pre[i][j] = cnt[j];
    }
    int l = 0, r = n * sn / st;
    while(l < r)
    {
        int mid = l + r + 1 >> 1;
        if(chk(mid)) l = mid;
        else r = mid - 1;
    }
    cout << l;

    return 0;
}

G

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

#define int ll

const int N = 2e5 + 5;
int n, a[N];

int nxt[N], pos[N], ans;

struct sgt
{
    int a[N << 2], c[N << 2], tg[N << 2];
    void pu(int x)
    {
        a[x] = min(a[x << 1], a[x << 1 | 1]);
        c[x] = 0;
        if(a[x << 1] == a[x]) c[x] += c[x << 1];
        if(a[x << 1 | 1] == a[x]) c[x] += c[x << 1 | 1];
    }
    void pd(int x)
    {
        if(tg[x])
        {
            a[x << 1] += tg[x], a[x << 1 | 1] += tg[x];
            tg[x << 1] += tg[x], tg[x << 1 | 1] += tg[x];
            tg[x] = 0;
        }
    }
    void upd(int ql, int qr, int l, int r, int x, int v)
    {
        if(ql <= l && r <= qr)
        {
            a[x] += v, tg[x] += v;
            return;
        }
        int mid = l + r >> 1; pd(x);
        if(mid >= ql) upd(ql, qr, l, mid, x << 1, v);
        if(mid < qr) upd(ql, qr, mid + 1, r, x << 1 | 1, v);
        pu(x);
    }
    void build(int l, int r, int x)
    {
        if(l == r) return c[x] = 1, void();
        int mid = l + r >> 1;
        build(l, mid, x << 1);
        build(mid + 1, r, x << 1 | 1);
        pu(x);
        // cerr << c[x] << endl;
    }
}t;

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    cin >> n;
    for(int i = 1; i <= n; i ++) cin >> a[i];
    // ans = n;
    t.build(1, n, 1);
    for(int i = n; i >= 1; i --)
    {
        if(!pos[a[i]]) nxt[i] = n + 1;
        else nxt[i] = pos[a[i]];
        pos[a[i]] = i;
    }
    for(int i = n; i >= 1; i --)
    {
        t.upd(i, n, 1, n, 1, 1);
        if(nxt[i] != n + 1)
        {
            if(nxt[nxt[i]] != n + 1)
            {
                t.upd(nxt[nxt[i]], n, 1, n, 1, 1);
            }
            t.upd(nxt[i], n, 1, n, 1, -2);
        }
        // cerr << t.c[1] << endl;
        if(t.a[1] == 0) ans += n - t.c[1];
        else ans += n;
    }
    cout << ans;

    return 0;
}
posted @   adam01  阅读(56)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示