QOJ#8079 Range Periodicity Query 题解

题意

给定一个长度为 \(n\) 的字符串 \(T\),按照以下规则生成一组字符串 \(S_{1\sim n}\):若 \(T_i\) 为小写,\(S_i=T_i+S_{i-1}\),否则 \(S_i=S_{i-1}+lower(T_i)\).

给定一个长度为 \(m\) 的序列 \(p\)\(q\) 次询问,求 \(p\) 上区间 \(l\sim r\) 中最小的为 \(S_k\) 的周期的数。

思路

首先发现一个关键性质,若一个长度不为 \(S_i\) 的周期,那它一定不为 \(S_j(i\le j)\) 的周期。

\(i\)\(S_{[i,t_i]}\) 的周期,可以考虑二分找到 \(t_i\).

然后可以使用线段树激活的方法,将 \(p\) 中的值按照 \(t_{p_i}\) 从大到小加入线段树中,将询问离线下来统计答案。

tips:本题似乎卡哈希(没试过,反正同学被卡了)。

code
#include <bits/stdc++.h>
#define int long long
#define chmax(x, y) x = max(x, y)
#define chmin(x, y) x = min(x, y)
#define SP << " " <<
#define fish signed
using namespace std;
mt19937 rnd(1209);
const int INF = 0x3f3f3f3f3f3f3f3f;
const int base = 66683, N = 1e6 + 10, base2 = 131, mod = 998244353;
unsigned long long prod[N], h[N];
long long prod2[N], h2[N];
unsigned long long get(int l, int r) {return h[r] - h[l - 1] * prod[r - l + 1];}
int get2(int l, int r) {return ((h2[r] - h2[l - 1] * prod2[r - l + 1] % mod) % mod + mod) % mod;}
int sl[N], sr[N], t[N]; char a[N];
int mn[N << 2];
#define ls(u) (u << 1)
#define rs(u) (u << 1 | 1)
void modify(int u, int l, int r, int pos, int k)
{
    if(l == r) {
        mn[u] = k;
        return ;
    }
    int mid = l + r >> 1;
    if(pos <= mid) modify(ls(u), l, mid, pos, k);
    else modify(rs(u), mid + 1, r, pos, k);
    mn[u] = min(mn[u << 1],mn[u << 1 | 1]);
}
int query(int u, int l, int r, int ql, int qr)
{
    if(ql <= l && r <= qr) return mn[u];
    int mid = l + r >> 1, res = INF;
    if(ql <= mid) chmin(res, query(ls(u), l, mid, ql, qr));
    if(qr > mid) chmin(res, query(rs(u), mid + 1, r, ql, qr));
    return res;
}
struct node {int l, r, id;} ;
int ans[N];
vector<node> vp[N];
vector<node> vq[N];
fish main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int n; cin >> n;
    int hh = n + 1, tt = n;
    for(int i = 1; i <= n; i ++)
    {
        char ch; cin >> ch;
        if('A' <= ch && ch <= 'Z') a[++ tt] = ch - 'A' + 'a';
        else a[-- hh] = ch;
        sl[i] = hh, sr[i] = tt;
    }
    prod[0] = prod2[0] = 1;
    for(int i = 1; i <= n; i ++) prod[i] = prod[i - 1] * base;
    for(int i = hh; i <= tt; i ++) h[i] = h[i - 1] * base + (unsigned long long)a[i];
    for(int i = 1; i <= n; i ++) prod2[i] = (prod2[i - 1] * base2) % mod;
    for(int i = hh; i <= tt; i ++) h2[i] = (h2[i - 1] * base2 % mod + a[i]) % mod;
    for(int i = 1; i <= n; i ++)
    {
        int l = i, r = n, res = i;
        while(l <= r)
        {
            int mid = l + r >> 1;
            int l1 = sl[mid], l2 = sl[mid] + i;
            int r1 = sr[mid] - i, r2 = sr[mid];
            if(get(l1, r1) == get(l2, r2) && get2(l1, r1) == get2(l2, r2)) l = mid + 1, res = mid;
            else r = mid - 1;
        }
        t[i] = res;
    }
    int m; cin >> m;
    for(int i = 1; i <= m; i ++) {int x; cin >> x; vp[t[x]].push_back({i, x});}
    memset(mn, 0x3f, sizeof mn);
    int q; cin >> q;
    for(int i = 1; i <= q; i ++) {int k, l, r; cin >> k >> l >> r; vq[k].push_back({l, r, i});}
    for(int i = n; i >= 1; i --)
    {
        for(auto v : vp[i]) modify(1, 1, m, v.l, v.r);
        for(auto v : vq[i]) {ans[v.id] = query(1, 1, m, v.l, v.r); if(ans[v.id] > i) ans[v.id] = -1;}
    }
    for(int i = 1; i <= q; i ++) cout << ans[i] << "\n";
    return 0;
}
posted @ 2024-11-27 09:19  lfyszy  阅读(129)  评论(0)    收藏  举报