题意就不赘述了。
分析:
设cnt[i]表示状态i共有多少串。
那么sum[i]表示状态i的贡献。
那么答案就是sigma(sum[i])
cnt[i]怎么求呢,建立完SAM后对于每一个状态建立拓扑图。
且若在拓扑图上有状态x到状态y的边。
然后拓扑排序的时候记录cnt[i],具体就是若x->y有边,则cnt[y] += cnt[x]。
则对于当前字符ch,有sum[y] += 10sum[x]+ch*cnt[x]。
于是就做完了。
#include <bits/stdc++.h>
#define sc(n) scanf("%d",&n)
#define pt(n) printf("%d\n",n)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define vi vector<int>
#define vl vector<long long>
#define pb push_back
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 2e6+7;
const int mod = 1e9+7;
int n;
string s;
ll sum[maxn<<1],cnt[maxn<<1],ind[maxn<<1],vis[maxn<<1];
struct node
{
int ch[11];
int len,fa;
}point[maxn<<2];
int las = 1,tot = 1;
void add(char c)
{
int p = las;
int np = las = ++tot;
point[np].len = point[p].len + 1;
for(;p && !point[p].ch[c];p=point[p].fa) point[p].ch[c] = np;
if(!p) point[np].fa = 1;
else
{
int q = point[p].ch[c];
if(point[q].len==point[p].len+1) point[np].fa = q;
else
{
int nq = ++tot;
point[nq] = point[q];
point[nq].len = point[p].len+1;
point[q].fa = point[np].fa = nq;
for(;p && point[p].ch[c]==q;p=point[p].fa) point[p].ch[c] = nq;
}
}
}
void makedeg()
{
queue<int> q;
q.push(1);
while(!q.empty())
{
int x = q.front();
q.pop();
for(int j=0;j<10;j++)
{
int y = point[x].ch[j];
if(!y) continue;
if(!vis[y])
{
q.push(y);
vis[y] = 1;
}
ind[y]++;
}
}
}
void topsort()
{
queue<int> q;
q.push(1);
cnt[1] = 1;
while(!q.empty())
{
int x = q.front();
q.pop();
for(int j=0;j<10;j++)
{
int y = point[x].ch[j];
if(!y) continue;
ind[y]--;
if(!ind[y]) q.push(y);
cnt[y] = (cnt[y]+cnt[x])%mod;
sum[y] = (sum[y]+10*sum[x]+j*cnt[x])%mod;
}
}
}
int main()
{
sc(n);
while(n--)
{
cin>>s;
for(int j=0;j<s.size();j++) add(s[j]-'0');
if(n) add(':'-'0');
}
makedeg();
topsort();
long long ans = 0;
for(int i=1;i<=tot;i++) ans = (ans+sum[i])%mod;
printf("%lld\n",ans%mod);
return 0;
}