• 【HDU-6230/2017CCPC哈尔滨A】Palindrome(式子转换+马拉车+主席树)


    题目链接:https://vjudge.net/problem/HDU-6230

    题目大意

    给定一个字符串,求这个字符串中有多少个一个半字符串

    一个半字符串:类似于1234543212345。

    花絮

    模拟赛时一直只思考了 123454321 怎么通过 (O(1)) 的时间复杂度搞出后面的串,导致直接卡死。

    思路

    1234543212345 是按照5和1对称的,那么在保证5和1是回文串的状态下,要能够之间相互覆盖。

    设5的位置为 (i),1的位置为 (j), 要求 (i leq j),则可得公式

    ( left{egin{matrix} j-i leq len[i] \ j-i leq len[j] \ end{matrix} ight. )

    移动式子,可得

    ( left{egin{matrix} j leq i+len[i] \ j-len[j] leq i \ end{matrix} ight. )

    将其转化为区间 ([i+1, i+len[i]]) 内求有多少个数,使得 (j-len[j] leq i)

    AC代码

    #include <bits/stdc++.h>
    
    typedef long long ll;
    using namespace std;
    const int MAXN = 5e5 + 5;
    
    class HJT {
    public:
        int ch[MAXN * 70][2], sum[MAXN * 70];
        int tot;
    
        void init() { tot = 0; }
    
        inline void push_up(int rt) {
            sum[rt] = sum[ch[rt][0]] + sum[ch[rt][1]];
        }
    
        int update(int rt, int pos, int val, int be, int en) {
            int nrt = ++tot;
            ch[nrt][0] = ch[nrt][1] = sum[nrt] = 0;
            if (be == en) {
                sum[nrt] = sum[rt] + val;
                return nrt;
            }
            int mid = (be + en) >> 1;
            if (pos <= mid) {
                ch[nrt][0] = update(ch[rt][0], pos, val, be, mid);
                ch[nrt][1] = ch[rt][1];
            } else {
                ch[nrt][0] = ch[rt][0];
                ch[nrt][1] = update(ch[rt][1], pos, val, mid + 1, en);
            }
            push_up(nrt);
            return nrt;
        }
    
        int query(int lrt, int rrt, int R, int be, int en) {
            if (R == en) return sum[rrt] - sum[lrt];
            int mid = (be + en) >> 1;
            if (R <= mid) {
                return query(ch[lrt][0], ch[rrt][0], R, be, mid);
            } else {
                return sum[ch[rrt][0]] - sum[ch[lrt][0]] + query(ch[lrt][1], ch[rrt][1], R, mid + 1, en);
            }
        }
    
    } tree;
    
    
    void Manacher(char s[], int len, char A[], int B[]) {
        int l = 0;
        A[l++] = '$';
        A[l++] = '#';
        for (int i = 0; i < len; i++) {
            A[l++] = s[i];
            A[l++] = '#';
        }
        A[l] = 0;
        int mx = 0, id = 0;
        for (int i = 0; i < l; i++) {
            B[i] = mx > i ? std::min(B[2 * id - i], mx - i) : 1;
            while (A[i + B[i]] == A[i - B[i]]) B[i]++;
            if (i + B[i] > mx) mx = i + B[i], id = i;
        }
    }
    
    char A[MAXN * 2];
    int B[MAXN * 2];
    
    char str[MAXN];
    int ren[MAXN], root[MAXN];
    
    int main() {
        int T;
        scanf("%d", &T);
        while (T--) {
            scanf("%s", str + 1);
            int n = strlen(str + 1);
            Manacher(str + 1, n, A + 1, B + 1);
    
            int maxR = 0;
            for (int i = 1; i <= n; i++) ren[i] = (B[i * 2 + 1] - 2) >> 1, maxR = max(maxR, i - ren[i]);
    
            tree.init();
            root[0] = 0;
            for (int i = 1; i <= n; i++) {
                root[i] = tree.update(root[i - 1], i - ren[i], 1, 1, maxR);
            }
            
            ll res = 0;
            for (int i = 1; i <= n; i++) {
                if (ren[i] == 0) continue;
              //  printf("%d %d %d %d
    ", i, i, i+ren[i], tree.query(root[i], root[i+ren[i]], i, 1, maxR));
                res = res + tree.query(root[i], root[i+ren[i]], i, 1, maxR);
            }
            printf("%lld
    ", res);
    
    //        for (int i = 1; i <= n; i++) {
    //            printf("%d ", ren[i]);
    //        }
    //        printf("
    ");
        }
    }
    
  • 相关阅读:
    前台调用后台方法循环绑定数据到前台
    禁用绑定在Repeater的控件
    Repeater,ItemDataBound事件,获取绑定列的值,给指定列添加js方法
    Oracle定时值执行存储过程
    A页面跳到B页面,B页面获取A页面的URL
    Jquery获取用户控件页面中控件的值
    Web页面获取用户控件页面中服务器控件的值
    springmvc静态资源;mvc:default-servlet-handler后Controller失效
    创建 Angular 8.0 项目
    window location跳转
  • 原文地址:https://www.cnblogs.com/tudouuuuu/p/14110588.html
Copyright © 2020-2023  润新知