QOJ.ac

QOJ

ID题目提交者结果用时内存语言文件大小提交时间测评时间
#771470#7876. Cyclic SubstringsExtractStarsTL 63ms232020kbC++177.2kb2024-11-22 13:19:062024-11-22 13:19:06

Judging History

你现在查看的是最新测评结果

  • [2024-11-22 13:19:06]
  • 评测
  • 测评结果:TL
  • 用时:63ms
  • 内存:232020kb
  • [2024-11-22 13:19:06]
  • 提交

answer

#include <bits/stdc++.h>

using namespace std;

#define ft first
#define sd second

#define yes cout << "yes\n"
#define no cout << "no\n"

#define Yes cout << "Yes\n"
#define No cout << "No\n"

#define YES cout << "YES\n"
#define NO cout << "NO\n"

#define pb push_back
#define eb emplace_back

#define all(x) x.begin(), x.end()
#define all1(x) x.begin() + 1, x.end()
#define unq_all(x) x.erase(unique(all(x)), x.end())
#define unq_all1(x) x.erase(unique(all1(x)), x.end())
#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3fLL

#define RED cout << "\033[91m"     // 红色
#define GREEN cout << "\033[92m"   // 绿色
#define YELLOW cout << "\033[93m"  // 蓝色
#define BLUE cout << "\033[94m"    // 品红
#define MAGENTA cout << "\033[95m" // 青色
#define CYAN cout << "\033[96m"    // 青色
#define RESET cout << "\033[0m"    // 重置

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef __int128_t i128;

typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ll, int> pli;
typedef pair<string, ll> psl;

typedef tuple<int, int, int> ti3;
typedef tuple<ll, ll, ll> tl3;
typedef tuple<ld, ld, ld> tld3;

typedef vector<bool> vb;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<string> vs;
typedef vector<vi> vvi;
typedef vector<vl> vvl;

// mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());

template <typename T>
inline T read()
{
    T x = 0;
    int y = 1;
    char ch = getchar();
    while (ch > '9' || ch < '0')
    {
        if (ch == '-')
            y = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = (x << 3) + (x << 1) + (ch ^ 48);
        ch = getchar();
    }
    return x * y;
}

template <typename T>
inline void write(T x)
{
    if (x < 0)
    {
        putchar('-');
        x = -x;
    }
    if (x >= 10)
    {
        write(x / 10);
    }
    putchar(x % 10 + '0');
}

/*#####################################BEGIN#####################################*/
const int mod = 998244353;

const int N = 3e6 + 5;
struct PAM
{
    string s;       // 存储当前处理的字符串,添加一个空格便于下标从1开始
    int n;          // 当前字符串的长度
    int nxt[N][10]; // 转移数组,nxt[i][c]表示从节点i通过字符c转移到的节点
    int fail[N];    // 后缀链接,fail[i]表示节点i的最长回文后缀的节点编号
    i128 len[N];    // 每个节点表示的回文串的长度
    i128 cnt[N];    // 每个节点对应的回文串在字符串中出现的次数
    // int sed[N];    // (可选)以当前节点为后缀的回文串的个数
    // int record[N]; // (可选)每个回文串在原串中出现的位置
    int tot;  // 当前回文自动机的节点总数
    int last; // 当前字符串的最长回文后缀对应的节点编号

    // 初始化回文自动机
    void init()
    {
        tot = 0;
        // 将所有数组初始化为0
        for (int i = 0; i < N; i++)
        {
            fail[i] = cnt[i] = len[i] = 0;
            for (int j = 0; j < 10; j++)
                nxt[i][j] = 0;
        }
    }

    // 创建一个新的节点,lenx为该节点表示的回文串的长度
    int newnode(int lenx)
    {
        for (int i = 0; i < 26; i++)
            nxt[tot][i] = 0; // 初始化转移数组
        cnt[tot] = 0;        // 初始化出现次数
        len[tot] = lenx;     // 设置回文串长度
        return tot;          // 返回新节点的编号
    }

    // 构建回文自动机的初始状态
    void build(string ss)
    {
        tot = 0;
        newnode(0); // 节点0:长度为0的回文串
        tot = 1;
        newnode(-1); // 节点1:长度为-1的虚拟节点,用于处理边界情况
        fail[0] = 1; // 节点0的后缀链接指向节点1
        n = ss.size();
        s = " " + ss; // 在字符串前添加空格,使下标从1开始
    }

    // 寻找可以扩展当前字符的最长回文后缀
    int getfail(int x, int pos)
    {
        // 不断沿着后缀链接寻找,直到找到满足条件的节点
        while (pos - len[x] - 1 < 0 || s[pos - len[x] - 1] != s[pos])
            x = fail[x];
        return x;
    }

    /*
    插入字符到回文自动机中
    cc: 当前字符
    pos: 当前字符的位置
    op: 操作类型,通常为1,表示插入
    */
    void insert(char cc, int pos, int op)
    {
        int c = cc - '0';           // 将字符转换为整数(假设字符是'0'到'9')
        int p = getfail(last, pos); // 找到可以扩展的节点

        // 如果通过字符c没有转移,则需要创建新的节点
        if (!nxt[p][c])
        {
            tot++;
            newnode(len[p] + 2);                       // 新回文串的长度为len[p] + 2
            fail[tot] = nxt[getfail(fail[p], pos)][c]; // 设置新节点的后缀链接
            len[tot] = len[p] + 2;                     // 再次设置长度(冗余,可删除)
            // sed[tot] = sed[fail[tot]] + 1;            // (可选)更新以当前节点为后缀的回文串个数
            nxt[p][c] = tot; // 更新转移
        }
        last = nxt[p][c]; // 更新当前最长回文后缀
        cnt[last] += op;  // 增加该回文串的出现次数
        // record[last] = pos;        // (可选)记录该回文串的出现位置
    }

    // 遍历整个字符串进行插入操作
    void insert()
    {
        for (int i = 1; i <= n; i++)
        {
            if (i <= n / 2)
                insert(s[i], i, 0); // 前半部分不计数(根据具体问题需求)
            else
                insert(s[i], i, 1); // 后半部分计数
        }
    }

    // 获取不同的回文子串的个数
    int get_diff_cnt()
    {
        return tot - 1; // 减去一个虚拟节点
    }

    // 获取所有回文子串的个数(允许重复计算)
    int get_all_cnt()
    {
        int sum = 0;
        calc();
        for (int i = 2; i <= tot; i++)
            sum += cnt[i];
        return sum;
    }
    i128 calc()
    {
        i128 ans = 0;
        // 从后往前遍历所有节点,累加出现次数
        for (int i = tot; i > 0; i--)
        {
            cnt[fail[i]] = (cnt[fail[i]] + cnt[i]) % mod; // 后缀链接节点累加当前节点的次数
            // 根据具体问题需求进行额外计算
            if (i >= 2 && len[i] <= n / 2)
            {
                ans = (ans + 1ll * cnt[i] * cnt[i] % mod * len[i] % mod) % mod;
            }
        }
        return ans;
    }
} pam;

void solve()
{
    int n;
    cin >> n;
    string s;
    cin >> s;
    s = s + s;
    pam.init();
    pam.build(s);
    pam.insert();
    write(pam.calc());
    putchar('\n');
}

int main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    // freopen("test.in", "r", stdin);
    // freopen("test.out", "w", stdout);
    int _ = 1;
    // cin >> _;
    while (_--)
    {
        solve();
    }
    return 0;
}

/*######################################END######################################*/
// 链接:

详细

Test #1:

score: 100
Accepted
time: 4ms
memory: 226520kb

input:

5
01010

output:

39

result:

ok 1 number(s): "39"

Test #2:

score: 0
Accepted
time: 16ms
memory: 226280kb

input:

8
66776677

output:

192

result:

ok 1 number(s): "192"

Test #3:

score: 0
Accepted
time: 8ms
memory: 226276kb

input:

1
1

output:

1

result:

ok 1 number(s): "1"

Test #4:

score: 0
Accepted
time: 3ms
memory: 226224kb

input:

2
22

output:

12

result:

ok 1 number(s): "12"

Test #5:

score: 0
Accepted
time: 4ms
memory: 226276kb

input:

2
21

output:

2

result:

ok 1 number(s): "2"

Test #6:

score: 0
Accepted
time: 11ms
memory: 226532kb

input:

3
233

output:

10

result:

ok 1 number(s): "10"

Test #7:

score: 0
Accepted
time: 7ms
memory: 226284kb

input:

3
666

output:

54

result:

ok 1 number(s): "54"

Test #8:

score: 0
Accepted
time: 63ms
memory: 232020kb

input:

1000000
3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333...

output:

496166704

result:

ok 1 number(s): "496166704"

Test #9:

score: -100
Time Limit Exceeded

input:

3000000
2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222...

output:


result: