题目链接

题意 : 给你一个串、要你将其划分成两个串、使得左边的串的本质不同回文子串的个数是右边串的两倍、对于每一个这样子的划分、其对答案的贡献就是左边串的长度、现在要你找出所有这样子的划分、并将贡献乘起来、答案 mod 1e9+7

分析 :

从左到右跑一边回文自动机、对于每个前缀

能够得出其有多少个本质不同的回文子串

本质不同的回文子串的个数实际上就是自动机节点数 - 2

那么跑一遍前缀之后我们能得到所有可作为左边部分串的本质不同回文子串的个数

因为是回文串、所以我们倒着跑一遍、就同样能得到作为右边部分串的本质不同回文子串的个数

最后暴力检查一遍对于每一个位置是否有符合题意的合理划分、如果有就将左边部分长度累乘起来

#include<bits/stdc++.h>
#define LL long long
#define ULL unsigned long long

#define scl(i) scanf("%lld", &i)
#define scll(i, j) scanf("%lld %lld", &i, &j)
#define sclll(i, j, k) scanf("%lld %lld %lld", &i, &j, &k)
#define scllll(i, j, k, l) scanf("%lld %lld %lld %lld", &i, &j, &k, &l)

#define scs(i) scanf("%s", i)
#define sci(i) scanf("%d", &i)
#define scd(i) scanf("%lf", &i)
#define scIl(i) scanf("%I64d", &i)
#define scii(i, j) scanf("%d %d", &i, &j)
#define scdd(i, j) scanf("%lf %lf", &i, &j)
#define scIll(i, j) scanf("%I64d %I64d", &i, &j)
#define sciii(i, j, k) scanf("%d %d %d", &i, &j, &k)
#define scddd(i, j, k) scanf("%lf %lf %lf", &i, &j, &k)
#define scIlll(i, j, k) scanf("%I64d %I64d %I64d", &i, &j, &k)
#define sciiii(i, j, k, l) scanf("%d %d %d %d", &i, &j, &k, &l)
#define scdddd(i, j, k, l) scanf("%lf %lf %lf %lf", &i, &j, &k, &l)
#define scIllll(i, j, k, l) scanf("%I64d %I64d %I64d %I64d", &i, &j, &k, &l)

#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define lowbit(i) (i & (-i))
#define mem(i, j) memset(i, j, sizeof(i))

#define fir first
#define sec second
#define VI vector<int>
#define ins(i) insert(i)
#define pb(i) push_back(i)
#define pii pair<int, int>
#define VL vector<long long>
#define mk(i, j) make_pair(i, j)
#define all(i) i.begin(), i.end()
#define pll pair<long long, long long>

#define _TIME 0
#define _INPUT 0
#define _OUTPUT 0
clock_t START, END;
void __stTIME();
void __enTIME();
void __IOPUT();
using namespace std;

struct Palindromic_Tree {
    ;
     ;

    deque<int> text;
    int len[maxn];///len[i]表示节点i表示的回文串的长度
    int cnt[maxn];///第 i 节点表示的回文串出现的次数、注意最后调用 getCnt 函数完成计算
    int num[maxn];///表示以节点 i 代表的回文串端点为端点的不同回文串个数
    int nxt[maxn][Letter];///nxt静态指针和字典树类似,指向的串为当前串两端加上同一个字符构成
    int fail[maxn];///失配指针
    int odd, even;///奇偶原始节点
    int pre, suf;
    int totNode;///自动机所有节点的个数
    LL totNum;///串中所有回文串数量

    int newNode(int _len){
        int ret = totNode++;
        len[ret] = _len;
        cnt[ret] = num[ret] = ;
        fail[ret] = ;
        memset(nxt[ret], , sizeof(nxt[ret]));
        return ret;
    }

    inline void init(){
        text.clear();
        totNode = ;
        totNum = ;
        even = newNode();
        odd = newNode(-);
        fail[even] = fail[odd] = odd;
        pre = suf = even;
    }

    int encode(char c){
        return c - 'a';
    }

    template<typename FunT>
    int getFail(int ch, int cur, FunT getNext){
        for(int i = getNext(len[cur]);
            i <  || i >= (int)text.size() || text[i] != ch;
            cur = fail[cur], i = getNext(len[cur]));
        return cur;
    }

    template<typename FunT>
    int Insert(int ch, int last, FunT getNext){
        last = getFail(ch, last, getNext);
        if(!nxt[last][ch]){
            );
            fail[cur] = nxt[getFail(ch, fail[last], getNext)][ch];
            nxt[last][ch] = cur;
            num[cur] = num[fail[cur]] + ;
        }

        last = nxt[last][ch];
        totNum += (LL)num[last];
        cnt[last]++;
        return last;
    }

    int push_front(char c){
        text.push_front(encode(c));
        pre = Insert(encode(c), pre, [](; });
        if(len[pre] == (int)text.size()) suf = pre;
        return totNode;
    }

    int push_back(char c){
        text.push_back(encode(c));
        suf = Insert(encode(c), suf, [; });
        if(len[suf] == (int)text.size()) pre = suf;
        return totNode;
    }

    int push_front(char *s){
        ;
        ; s[i]; i++)
            ret = push_front(s[i]);
        return ret;
    }

    int push_back(char *s){
        ;
        ; s[i]; i++)
            ret = push_back(s[i]);
        return ret;
    }

    inline void getCnt(){
        ; i>=; i--)
            cnt[fail[i]] += cnt[i];
    }

}PAM1, PAM2;

;
;

char str[maxn];
LL L[maxn], R[maxn];

int main(void){__stTIME();__IOPUT();

    int T;
    sci(T);
    while(T--){
        mem(L, );
        mem(R, );
        PAM1.init();
        PAM2.init();
        scs(str);
        int len = strlen(str);
        ; i<len; i++){
            PAM1.push_back(str[i]);
            L[i] = PAM1.totNode - ;
        }
        ; i>=; i--){
            PAM2.push_back(str[i]);
            R[i] = PAM2.totNode - ;
        }

        LL ans = ;
        ; i<len; i++){
             * R[i+]){
                ) ans = 1LL;
                ans = (1LL * (i+) * ans) % mod;
            }
        }

        printf("%lld\n", ans);
    }

__enTIME();;}

void __stTIME()
{
    #if _TIME
        START = clock();
    #endif
}

void __enTIME()
{
    #if _TIME
        END = clock();
        cerr<<"execute time = "<<(double)(END-START)/CLOCKS_PER_SEC<<endl;
    #endif
}

void __IOPUT()
{
    #if _INPUT
        freopen("in.txt", "r", stdin);
    #endif
    #if _OUTPUT
        freopen("out.txt", "w", stdout);
    #endif
}

WHU 583 Palindrome ( 回文自动机 && 本质不同的回文串的个数 )的更多相关文章

  1. 【回文自动机】bzoj3676 [Apio2014]回文串

    回文自动机讲解!http://blog.csdn.net/u013368721/article/details/42100363 pam上每个点代表本质不同的回文子串.len(i)代表长度,cnt(i ...

  2. hdu多校第二场1009 (hdu6599) I Love Palindrome String 回文自动机/字符串hash

    题意: 找出这样的回文子串的个数:它本身是一个回文串,它的前一半也是一个回文串 输出格式要求输出l个数字,分别代表长度为1~l的这样的回文串的个数 题解: (回文自动机和回文树是一个东西) 首先用回文 ...

  3. 洛谷P5496 回文自动机【PAM】模板

    回文自动机模板 1.一个串的本质不同的回文串数量是\(O(n)\)级别的 2.回文自动机的状态数不超过串长,且状态数等于本质不同的回文串数量,除了奇偶两个根节点 3.如何统计所有回文串的数量,类似后缀 ...

  4. bzoj千题计划306:bzoj2342: [Shoi2011]双倍回文 (回文自动机)

    https://www.lydsy.com/JudgeOnline/problem.php?id=2342 解法一: 对原串构建回文自动机 抽离fail树,从根开始dfs 设len[x]表示节点x表示 ...

  5. [BZOJ4044]Virus synthesis 回文自动机的DP

    4044: [Cerc2014] Virus synthesis Time Limit: 20 Sec  Memory Limit: 128 MB Description Viruses are us ...

  6. bzoj 2084: Antisymmetry 回文自动机

    题目: Description 对于一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一样,就称作"反对称"字符串.比如00001111和010101就是反对称的 ...

  7. 【CF932G】Palindrome Partition 回文自动机

    [CF932G]Palindrome Partition 题意:给你一个字符串s,问你有多少种方式,可以将s分割成k个子串,设k个子串是$x_1x_2...x_k$,满足$x_1=x_k,x_2=x_ ...

  8. 2019牛客暑期多校训练营(第六场)C - Palindrome Mouse (回文自动机)

    https://ac.nowcoder.com/acm/contest/886/C 题意: 给出一个串A , 集合S里面为A串的回文字串 , 现在在集合S里面找出多少对(a,b),b为a的字串 分析: ...

  9. HDU-6599 I Love Palindrome String(回文自动机+字符串hash)

    题目链接 题意:给定一个字符串\(|S|\le 3\times 10^5\) 对于每个 \(i\in [1,|S|]\) 求有多少子串\(s_ls_{l+1}\cdots s_r\)满足下面条件 \( ...

随机推荐

  1. (十八)JDBC获取存储过程和主键

    目录 获取数据库自动生成的主键: JDBC调用存储过程 获取数据库自动生成的主键: update 更新操作以后,如果需要用到结果集,可以通过 PreparedStatement.getResultSe ...

  2. NOIP2012 借教室 题解 洛谷P1083

    一看就是暴力 好吧,其实是线段树或差分+二分,这里用的是差分+二分的做法. 二分部分的代码,套个二分板子就行 ,right=m; while(left<right)//二分 { ; ; else ...

  3. Two progressions(CodeForces-125D)【鸽巢原理】

    题意:将一列数划分为两个等差数列. 思路:首先,我要吹爆鸽巢原理!!!真的很强大的东西!!! 加入能完成题设操作,则前三个数中,必有至少两个数在同一序列,枚举三种情况(a1 a2,a2 a3,a1 a ...

  4. (转)如何真正实现由文档驱动的API设计?

    前言 本文主要介绍了一种新的开发思路:通过反转开发顺序,直接从API文档中阅读代码.作者认为通过这种开发方式,你可以更清楚地知道文档表达出什么以及它应该如何实现. 如果单从API文档出发,由于信息量不 ...

  5. MySQL 官方样板数据库sakila

    Sakila示例数据库最初由MySQL AB文档团队的前成员Mike Hillyer开发,旨在提供可用于书籍,教程,文章,样本等示例的标准模式. Sakila示例数据库还用于突出MySQL的最新功能, ...

  6. jemeter鬓发压力测试包

    使用: 为子线程添加响应时间:https://www.cnblogs.com/duanxz/p/5464993.html 结果查看分析:聚合报告在监听器里面: https://wenku.baidu. ...

  7. Django rest-framework框架-版本控制

    第一版: from rest_framework.versioning import BaseVersioning class ParamVersion(object): def determine_ ...

  8. spring利用xml配置定时任务

    在开发中会经常遇到做定时任务的需求,例如日志定时清理与处理,数据信息定时同步等需求. 1.在spring中利用xml配置定时任务,如下 <!-- ftpiptv信息同步接口定时任务配置--> ...

  9. 基于Hadoop生态SparkStreaming的大数据实时流处理平台的搭建

    随着公司业务发展,对大数据的获取和实时处理的要求就会越来越高,日志处理.用户行为分析.场景业务分析等等,传统的写日志方式根本满足不了业务的实时处理需求,所以本人准备开始着手改造原系统中的数据处理方式, ...

  10. 【温故知新】php 魔术方法

    <?php class Magic{ private $name; /** *构造方法,在类被实例化时自动调用,一般用于初始化操作 */ public function __construct( ...