zoukankan      html  css  js  c++  java
  • 洛谷P4555 [国家集训队]最长双回文串(manacher 线段树)

    题意

    题目链接

    Sol

    我的做法比较naive。。首先manacher预处理出以每个位置为中心的回文串的长度。然后枚举一个中间位置,现在要考虑的就是能覆盖到i - 1的回文串中 中心最靠左的,和能覆盖到i+1中 中心最靠右的,算一下答案取个max。

    线段树维护一下区间min, max。标记永久化炒鸡好写

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN = 1e6 + 10, INF = 1e9 + 10;
    char s[MAXN];
    int len[MAXN], N, ans[MAXN];
    template<typename A, typename B> inline void chmax(A &x, B y) {
        x = x < y ? y : x;
    }
    template<typename A, typename B> inline void chmin(A &x, B y) {
        x = x < y ? x : y;
    }
    int root, ls[MAXN], rs[MAXN], mn[MAXN], mx[MAXN], tot;
    void Max(int &k, int l, int r, int ql, int qr, int v) {
    	if(!k) k = ++tot, mn[k] = INF;
    	if(ql <= l && r <= qr) {chmax(mx[k], v); return ;}
    	int mid = l + r >> 1;
    	if(ql <= mid) Max(ls[k], l, mid, ql, qr, v);
    	if(qr  > mid) Max(rs[k], mid + 1, r, ql, qr, v);
    }
    void Min(int &k, int l, int r, int ql, int qr, int v) {
    	if(!k) k = ++tot, mn[k] = INF;
    	if(ql <= l && r <= qr) {chmin(mn[k], v); return ;}
    	int mid = l + r >> 1;
    	if(ql <= mid) Min(ls[k], l, mid, ql, qr, v);
    	if(qr  > mid) Min(rs[k], mid + 1, r, ql, qr, v);
    }
    int QueryMx(int k, int l, int r, int p) {
    	int ans = mx[k];
    	if(l == r) return ans;
    	int mid = l + r >> 1;
    	if(p <= mid) chmax(ans, QueryMx(ls[k], l, mid, p));
    	else chmax(ans, QueryMx(rs[k], mid + 1, r, p));
    	return ans;
    }
    int QueryMn(int k, int l, int r, int p) {
    	int ans = mn[k];
    	if(l == r) return ans;
    	int mid = l + r >> 1;
    	if(p <= mid) chmin(ans, QueryMn(ls[k], l, mid, p));
    	else chmin(ans, QueryMn(rs[k], mid + 1, r, p));
    	return ans;
    }
    void trans() {
        static char tmp[MAXN];
        for(int i = 1; i <= N; i++) {
            tmp[2 * i - 1] = s[i];
            tmp[2 * i] = '#';
        }
        memcpy(s, tmp, sizeof(s));
        N = (N << 1) - 1;
    	int mx = 0, id = 0;
    	for(int i = 1; i <= N; i++) {
    		ans[i] = (mx > i ? min(mx - i, ans[id * 2 - i]) : 1);
    		while(s[i - ans[i]] == s[i + ans[i]]) ans[i]++;
    		if(i + ans[i] > mx) mx = i + ans[i], id = i;
    		Max(root, 1, N, i - ans[i] + 1, i, i);
    		Min(root, 1, N, i, i + ans[i] - 1, i);
    	}
    }
    int main() {
        scanf("%s", s + 1);
        N = strlen(s + 1);
        trans();
        int ans = 0;
        for(int i = 2; i <= N; i += 2) {
            chmax(ans, (i - 1 - QueryMn(root, 1, N, i - 1)) + 1 + (QueryMx(root, 1, N, i + 1) - i - 1) + 1);
        }
        cout << ans;
        return 0;
    }
    
  • 相关阅读:
    Java 期末考试
    Java 方法重载,方法重写(覆盖),继承等细节注意
    Java 方法(变量)修饰符的使用顺序
    java考试易错题大全
    python获取进程id号:
    C语言如何判断单个数字是否溢出:
    VS2017编译错误:#error: Building MFC application with /MD[d] (CRT dll version) requires MFC shared dll version
    VS2017出现不存在从"CString"到"const char*"的适当转换函数
    Python实现将图片以二进制格式保存到MySQL数据库中,以及取出:
    解决springboot 出现异常: java.net.BindException: Address already in use: bind
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/10373538.html
Copyright © 2011-2022 走看看