首页 > 其他分享 >HDU7326 string magic(Easy Version)

HDU7326 string magic(Easy Version)

时间:2023-08-13 13:11:49浏览次数:42  
标签:magic int tr HDU7326 Version fail now PAM size

HDU7326 string magic(Easy Version)

tag:回文自动机

题目链接

题意:

多组样例,每组输入一字符串(长度1e5以内),输出满足下列条件的子串个数: 该串由两个完全相同的回文串拼接而成

做法:

字符串的题目一般都比较板,洛谷的P4287可以说是这道题目的原题,我们先看看原题是怎么做的


P4287 双倍回文

题意:

给出字符串,输出满足下列条件的最大子串长度:

  • 字符串x由两个完全相同的回文串拼接而成
  • 字符串x长度为4的倍数

做法:

  • 我们使用回文自动机建立fail树,同时用vector存边准备dfs
  • 我们直到树上一个节点就代表着一种回文串,节点父亲所代表的字符串则是当前节点的最长后缀回文,那么显然节点的祖先都是该点的后缀回文
  • 于是我们可以在dfs的过程中计入祖先节点的长度,若存在当前节点一半长度的祖先,且当前节点长度为4的倍数,那么当前就是一个合法串。

代码

#define fst std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout << std::fixed << std::setprecision(20)
#define le "\n"
#define ll long long 
#include <bits/stdc++.h>
using namespace std;
const int N=5e5+50;
const int mod=998244353;
const ll inf = 2e18;

namespace PAM {
    int size, tot, last;
    int cnt[N], tr[N][26], len[N], fail[N],f[N];
    char s[N];
    vector<int> g[N];
    int ans = 0;

    int node(int l) {  // 建立一个新节点,长度为 l
        size++;
        memset(tr[size], 0, sizeof(tr[size]));
        len[size] = l;
        fail[size] = cnt[size] = 0;
        return size;
    }

    void init() {  // 初始化
        size = -1; last = 0;
        s[tot = 0] = '$';
        node(0); node(-1);
        g[1].push_back(0);
        fail[0] = 1;
    }

    int getfail(int x) {  // 找后缀回文
        while (s[tot - len[x] - 1] != s[tot]) x = fail[x];
        return x;
    }

    void add(char c) {  // 建树
        s[++tot] = c;
        int now = getfail(last);
        if(!tr[now][c]){
            int x = node(len[now] + 2);
            fail[x] = tr[getfail(fail[now])][c]; 
            g[fail[x]].push_back(x);
            tr[now][c] = x;
        }
        last = tr[now][c];
        cnt[last]++;
    }

    void dfs(int u){
        for(auto i: g[u]){
            int k = len[i];
            f[k]++;
            if(k%4==0&&f[k/2]) ans = max(ans,k);
            dfs(i);
            f[k]--;
        }
    }
}


int main(){
    PAM::init();
    int n; cin>>n;
    for(int i=1;i<=n;i++){
        char c; cin>>c;
        PAM::add(c-'a');
    }

    PAM::dfs(1);
    cout<<PAM::ans<<le;

    return 0;
}

  • 回到当前这题,判断合法串的方式可以说是几乎一模一样,但是这次我们需要统计的是出现次数,在造完PAM之后,cnt计入的是最长回文个数,回文的子串并没有统计
  • 要算出所有回文串的个数可以通过dfs,或者直接从后往前做后缀和,因为父亲节点一定比儿子节点的编号小。

代码:

#define fst std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout << std::fixed << std::setprecision(20)
#define le "\n"
#define ll long long 
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+50;
const int mod=998244353;
const ll inf = 2e18;

namespace PAM {
    int size,tot,last,ans,n;
    int cnt[N], tr[N][26], len[N], fail[N],f[N];
    char s[N];
    vector<int> g[N];

    int node(int l) {  // 建立一个新节点,长度为 l
        size++;
        memset(tr[size], 0, sizeof(tr[size]));
        len[size] = l;
        fail[size] = cnt[size] = 0;
        return size;
    }

    void init() {  // 初始化
        size = -1; last = 0;
        ans = 0;
        s[tot = 0] = '$';
        node(0); node(-1);
        g[1].push_back(0);
        fail[0] = 1;
    }

    int getfail(int x) {  // 找后缀回文
        while (s[tot - len[x] - 1] != s[tot]) x = fail[x];
        return x;
    }

    void add(char c) {  // 建树
        s[++tot] = c;
        int now = getfail(last);
        if(!tr[now][c]){
            int x = node(len[now] + 2);
            fail[x] = tr[getfail(fail[now])][c]; 
            g[fail[x]].push_back(x);
            tr[now][c] = x;
        }
        last = tr[now][c];
        cnt[last]++;
    }

    void dfs(int u){
        for(auto i: g[u]){
            int k = len[i];
            f[k]++;
            if(k>=2&&k%2==0&&f[k/2]) ans += cnt[i];
            dfs(i);
            f[k]--;
        }
    }

    void cl(){
        for(int i=0;i<=size;i++) g[i].clear();
    }
}

void solve(){
    string s; cin>>s;
    PAM::init();
    for(auto i: s) PAM::add(i-'a');
    for(int i=PAM::size;i>=2;i--) PAM::cnt[PAM::fail[i]] += PAM::cnt[i]; 
    PAM::dfs(1);
    cout<<PAM::ans<<le;
    PAM::cl();
}

int main(){
    int t; cin>>t;
    while(t--){
        solve();
    }

    return 0;
}
   

标签:magic,int,tr,HDU7326,Version,fail,now,PAM,size
From: https://www.cnblogs.com/touchfishman/p/17626434.html

相关文章

  • 1、编译 glibc 过程中报错 ../configure --prefix=/opt/glibc-2.27       2、首
    64位安装包,查看系统位数,安装对应的mysqlLinux系统安装MySQL时,将MySQL-5.6.17-1.el6.x86_64.rpm-bundle.tar包打开,有7个rpm文件,如下:MySQL-client-5.6.17-1.el6.x86_64.rpmMySQL-devel-5.6.17-1.el6.x86_64.rpmMySQL-embedded-5.6.17-1.el6.x86_64.rpmMySQL-server-5.6.17-1.el6.......
  • could not find boost (missing iostreams) (found version xxxx)
    具体报错信息如上图,通过终端指定-DBOOST_LIBRARYDIR是无效的,需要在cmakelis中修改。注意这里报错溯源是cmakelistline29,所以修改如下set(CMAKE_INCLUDE_PATH${CMAKE_INCLUDE_PATH}"/home/rzhang/del/include")###新增set(CMAKE_LIBRARY_PATH${CMAKE_LIBRARY_PATH}"/h......
  • TLS X509 Version3.0
    ######################################################创建CAX509version3.0根证书#####################################################rm-rf/k8s/tlsv1CertPath=/k8s/tlsv1CertPD=huawei@123DomainName=ca.huawei.com#1、创建证书存放目录mkdir-p${......
  • 在Python中使用LooseVersion进行软件版本号比对
    技术背景Python是一门极其热门、极其灵活的开发语言,其更新迭代的速度也非常的快速。有时候我们遇到不同的软件版本不同方法处理的情况,此时就需要用到版本号比对的工具。举一个例子说,我们要在python代码中区分numpy版本在1.21.6之前和之后的版本。虽然我们可以自己手写一个软件版......
  • C1. Dual (Easy Version)
    link像这种构造题可以先分类讨论一波比如说全是正数或者全是负数,那么显然的就是可以用前缀和和后缀和来解决。而如果有正有负呢?可以注意到的是数字非常小,而\(2^5=32>20\)了,那么我们就可以先随便找到一个正数,把他自加上5次,然后第二个数加上它2次之后的数加上前面的数两次,这样结......
  • 遇到的问题----java Unsupported major.minor version 51.0
     Unsupportedmajor.minorversion51.0不同的JDK版本使用的major.minor不同,所以会导致这个错误。编译器运行的jdk选择版本和使用的jdk版本号应该对应。解决起来也很方便:打开exclipse中项目上的属性—javacompiler–选择一个合适的版本后重新编译即可。具体步骤解决:项目------......
  • 解决ls: relocation error: /lib64/libacl.so.1: symbol getxattr, version ATTR_1.0
    这个问题是在我conda装了一个包之后就出现了,ls等最基础的命令没有办法用了,网上的帖子也没有很好解决我的问题,而且我试了把我刚刚安的包删掉也没有解决,后面仔细分析一下这个报错,猜测应该是包安装的过程中本地conda中的一些依赖与系统中的一些起了冲突。通过ldd/lib64/libacl.so......
  • How to update to the latest Python version On Linux All In One
    HowtoupdatetothelatestPythonversionOnLinuxAllInOneupdatetothelatestPythonversiononRaspberryPierrorsold$python--versionPython3.9.2new$sudoaptupdate$aptlist|greppython3.10WARNING:aptdoesnothaveastableCL......
  • E1. PermuTree (easy version)
    E1.PermuTree(easyversion)Thisistheeasyversionoftheproblem.Thedifferencesbetweenthetwoversionsaretheconstrainton$n$andthetimelimit.Youcanmakehacksonlyifbothversionsoftheproblemaresolved.Youaregivenatreewith$n$......
  • /lib64/libstdc++.so.6: version `GLIBCXX_3.4.26' not found
    原因使用的gcc没有找到对应的glib库。每个版本的glib都会有改变,所以使用的时候必须匹配。大部分是因为自己编译升级了gcc,再用新的gcc编译程序时没有找到当时匹配的类库。查找原因报错提示很明确了,/lib64/libstdc++.so.6中没有找到GLIBCXX_3.4.26版本内容。正常情况/lib64/lib......