ACM-ICPC 2018 南京賽區網路預賽 I. Skr
阿新 • • 發佈:2019-02-16
題解
題目大意 給你一個數字串 問這個串的所有子段中是迴文串且不重複的值相加的和 結果模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];
}
}