zoukankan      html  css  js  c++  java
  • Finding Palindromes(POJ 3376)

    Sample Input

    3
    1 a
    2 ab
    2 ba
    

    Sample Output

    5
    

    Hint

    The 5 palindromes are:
    aa aba aba abba baab
    

    题意

    给定一系列字符串,询问它们能组成多少种回文(两两字符相连接,且满足自身与自身组合)
    

    思路

    对于字符串s和t,有三种情况它们可以组成一个回文;
          1.|s| > |t|, t的反串作为s的前缀,s的后缀为一个回文
                abcc
                ba
          2.|t| > |s|, s作为t反串的前缀, t的前缀为一个回文(保证翻转后该段不变)
                ab
                ccba
          3.s == t, 且s, t本身就是回文
                aa
                aa
          我们可以用manacher计算出每一个串在哪个节点之后均为回文,并将其插入到trie中在
    对应的后缀为回文的节点上进行标记(后缀为回文就加一),最后当我们用一个字符串来
    进行匹配时只需要加上这个字符串末尾位置的答案即可;
          但是上面的操作我们只计算了第一种情况,我们可以在将所有串进行翻转后在插入到trie
    中在进行一次上述操作,但是这一次我们会将第三中情况多算一遍,所以统计时需要减去这部分的
    值
    样例:
          aa
          ab
          ccab
          abcc
    

    代码

    #pragma GCC optimize(2)
    // #include<unordered_map>
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<string>
    #include<vector>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<map>
    #include<set>
    #define Buff ios::sync_with_stdio(false)
    #define rush() int Case = 0; int T; cin >> T;  while(T--)
    #define rep(i, a, b) for(int i = a; i <= b; i ++)
    #define per(i, a, b) for(int i = a; i >= b; i --)
    #define reps(i, a, b) for(int i = a; b; i ++)
    #define clc(a, b) memset(a, b, sizeof(a))
    #define Buff ios::sync_with_stdio(false)
    #define readl(a) scanf("%lld", &a)
    #define readd(a) scanf("%lf", &a)
    #define readc(a) scanf("%c", &a)
    #define reads(a) scanf("%s", a)
    #define read(a) scanf("%d", &a)
    #define lowbit(n) (n&(-n))
    #define pb push_back
    #define sqr(x) x*x
    #define lson rt<<1
    #define rson rt<<1|1
    #define ls lson, l, mid
    #define rs rson, mid+1, r
    #define y second
    #define x first
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int>PII;
    const int mod = 1e9+7;
    const double eps = 1e-6;
    const int N = 2e6+7;
    ll res;
    char s[N], t[N<<1];
    int f[N<<1], tr[N][26], val[N];
    int start[N], w[N], idx, cnt[N], len[N];
    void insert(char* str, int len)
    {
        int p = 0;
        // for(int i = 1; i <= len; i ++)
        //     cout << str[i];puts("");
        for(int i = 1; i <= len; i ++)
        {
            int t = str[i] - 'a';
            if(!tr[p][t])   tr[p][t] = ++idx;
            p = tr[p][t];
            val[p] += w[i];
            // printf("val[%d]: %d
    ", p, val[p]);
        }
        cnt[p] ++;
    }
    void manacher(char* str, int len)
    {
        int pos = 0, maxr = 0;
        int n = 0;
        t[n] = '%';
        for(int i = 1; i <= len; i ++)
        {
            t[++n] = '#';
            t[++n] = str[i];
            w[i] = 0;
        }
        t[++n] = '#';
        t[n+1] = 0;
        // cout << t+1 <<endl;
        for(int i = 1; i <= n; i ++)
        {
            f[i] = i < maxr ? min(f[pos*2-i], maxr-i):1;
            while(t[i-f[i]] == t[i+f[i]])   f[i] ++;
            if(maxr < i+f[i])   pos = i, maxr = i+f[i];
            if(i+f[i] > n)  
                w[(i-f[i])/2] = 1;
        }
        insert(str, len);
    }
    int find(char* s, bool op)
    {
        int p = 0;
        reps(i, 1, s[i])
        {
            int t = s[i] - 'a';
            if(!tr[p][t])   return 0;
            p = tr[p][t];
        }
        return op ? cnt[p] : val[p];
    }
    void search(int st, int en,bool op)
    {
        int n = 0;
        per(i, en, st)  t[++n] = s[i];
        t[n+1] = 0;
        // cout << t+1 <<endl;
        // cout << "flag0" << endl;
        // cout << find(t, 0) <<endl;
        res += find(t, 0);
        if(op)  
        {
            res -= find(t, 1);
            // cout << "flag1: " << endl;
            // cout << find(t, 1) <<endl;
        }
    }
    void init()
    {
        idx = 0;
        clc(tr, 0);
        clc(cnt, 0);
        clc(val, 0);
    }
    void rever(int st, int en)
    {
        while(st <= en)
        {
            swap(s[st], s[en]);
            st ++;
            en --;
        }
    }
    int main()
    {
        Buff;
        int n, l = 1;
        cin >> n;
        rep(i, 1, n)
        {
            cin >> len[i] >> (s+l);
            start[i] = l;
            manacher(s+l-1, len[i]);
            l += len[i];
        }
        rep(i, 1, n)
            search(start[i], start[i]+len[i]-1, 0);
        init();
        rep(i, 1, n)
        {
            rever(start[i], start[i]+len[i]-1);
            manacher(s+start[i]-1, len[i]);
        }
        rep(i, 1, n)
            search(start[i], start[i]+len[i]-1, 1);
        cout << res <<endl;
        return 0;
    }
    
  • 相关阅读:
    重写Django登录认证,实现用户名或者手机均可登录
    Django media文件夹详解
    Django admin使用
    python极验验证部署
    django 分页
    模板语言控制往哪个地址提交时,如果不填,默认往当前地址提交,也可以用request方法获取当前地址提交
    HashMap、Hashtable、LinkedHashMap、TreeMap、ConcurrentHashMap的区别
    ArrayList、LinkedList、Vector、CopyOnWriteArrayList的区别和源码分析
    谈谈线程池的核心参数,描述核心流程、应该怎么正确使用
    深入CAS的底层实现机制,以及对应的使用风险
  • 原文地址:https://www.cnblogs.com/Farrell-12138/p/13957185.html
Copyright © 2011-2022 走看看