ACM-ICPC 2018 南京赛区网络预赛 I. Skr

题解

题目大意 给你一个数字串 问这个串的所有子段中是回文串且不重复的值相加的和 结果模1e9+7

使用回文树模版 回文树可以统计有多少个不相同的字符串 在创建新节点的时候说明出现了一个新的不重复的回文 将每个新节点的值加入答案
新节点的值等于当前节点数字*pow(10, 当前节点长度-1) + 父节点值*10 + 当前节点值

AC代码

#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int MAXN = 2e6 + 10;
const int MAXC = 10;
int nxt[MAXN][MAXC], fal[MAXN], len[MAXN], idx, last; //子节点 最长回文后缀 回文长度 编号 最后处理位置
char s[MAXN];
ll ans, val[MAXN];

ll mpow(ll a, ll n, ll m)
{
    ll t = 1;
    while (n)
    {
        if (n & 1)
            t = (t * a) % m;
        a = (a * a) % m, n >>= 1;
    }
    return t;
}
inline int GetID(char c) //字符映射
{
    return c - '0';
}
void Build() //初始化根节点信息
{
    len[0] = 0, len[1] = -1;
    idx = 1, last = 0;
    fal[0] = 1;
}
int GetFail(char *s, int x, int n) //寻找最长的回文后缀
{
    while (s[n - len[x] - 1] != s[n])
        x = fal[x];
    return x;
}
void Insert(char *s, int n) //按照顺序插入一个字符串
{
    for (int i = 0; i < n; i++)
    {
        int c = GetID(s[i]);
        int p = GetFail(s, last, i);
        if (!nxt[p][c])
        {
            ++idx;
            len[idx] = len[p] + 2;
            fal[idx] = nxt[GetFail(s, fal[p], i)][c];
            nxt[p][c] = idx;
            if (p == 1) //父节点奇根
                val[idx] = c;
            else
                val[idx] = (c * mpow(10, len[idx] - 1, MOD) + val[p] * 10 + c) % MOD;
            ans = (ans + val[idx]) % MOD; //每个新节点计算答案
        }
        last = nxt[p][c];
    }
}

猜你喜欢

转载自blog.csdn.net/CaprYang/article/details/82683278