1. 程式人生 > >ACM-ICPC 2018 南京賽區網路預賽 I. Skr

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]; } }