str2int

\[Time Limit: 3000 ms\quad Memory Limit: 131072 kB
\]

题意

给出 \(n\) 个串,求出这 \(n\) 个串所有子串代表的数字的和。

思路

首先可以把这些串合并起来,串与串之间用没出现过的字符分隔开来,然后构建后缀自动机,因为后缀自动机上从 \(root\) 走到的任意节点都是一个子串,所有可以利用这个性质来做。

一开始我的做法是做 \(dfs\),令 \(dp[i]\) 表示节点 \(i\) 的贡献,转移就是 \(dp[v] = dp[v]+tmp*10+j\),表示从 \(root\) 到 \(u\) 的权值是\(tmp\),\(v\) 是 \(u\) 往 \(j\)走的下一个点。结果显然超时了。

我们发现对于\(dp[u]->dp[v]\)过程,如果之前走到 \(dp[u]\) 的有 \(12\),\(2\) 两步,假设现在往 \(3\) 这条边走,得到 \(12*10+3\),\(2*10+3\),那么其实这些值的贡献是可以一次性计算的,无论之前走到 \(dp[u]\) 的有几条路,都需要让他们全部 \(*10\),而 \(3\) 的贡献则是由走到 \(dp[u]\) 的路径数确定的。

那么我们就可以得到第二个方程:

  1. \(dp1[i]\) 表示节点 \(i\) 的贡献
  2. \(dp2[i]\) 表示之前有多少种方案走到 \(i\)
  3. \(dp1[v] = dp1[v] + dp1[u]*10 + dp2[u]*j\)
  4. \(dp2[v] = dp[2[v] + dp2[v]\)

最后为了去除前导零,只要控制从 \(root\) 出来的边最少从 \(1\) 开始就可以了。

如此计算后,\(\sum dp1[i]\) 就是最后的答案。

#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lowbit(x) x & (-x)
#define mes(a, b) memset(a, b, sizeof a)
#define fi first
#define se second
#define pii pair<int, int>
#define INOPEN freopen("in.txt", "r", stdin)
#define OUTOPEN freopen("out.txt", "w", stdout) typedef unsigned long long int ull;
typedef long long int ll;
const int maxn = 2e5 + 10;
const int maxm = 1e5 + 10;
const ll mod = 2012;
const ll INF = 1e18 + 100;
const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-8;
using namespace std; int n, m;
int cas, tol, T; struct Sam {
struct Node {
int next[20];
int fa, len;
void init() {
mes(next, 0);
fa = len = 0;
}
} node[maxn<<1];
int dp1[maxn<<1], dp2[maxn<<1];
bool vis[maxn<<1];
int tax[maxn<<1], gid[maxn<<1];
int last, sz;
void init() {
mes(dp1, 0);
mes(dp2, 0);
last = sz = 1;
node[sz].init();
}
void insert(int k) {
int p = last, np = last = ++sz;
node[np].init();
node[np].len = node[p].len + 1;
for(; p&&!node[p].next[k]; p=node[p].fa)
node[p].next[k] = np;
if(p == 0) {
node[np].fa = 1;
} else {
int q = node[p].next[k];
if(node[q].len == node[p].len+1) {
node[np].fa = q;
} else {
int nq = ++sz;
node[nq] = node[q];
node[nq].len = node[p].len+1;
node[np].fa = node[q].fa = nq;
for(; p&&node[p].next[k]==q; p=node[p].fa)
node[p].next[k] = nq;
}
}
}
void solve() {
int ans = 0;
for(int i=0; i<=sz; i++) tax[i] = 0;
for(int i=1; i<=sz; i++) tax[node[i].len]++;
for(int i=1; i<=sz; i++) tax[i] += tax[i-1];
for(int i=1; i<=sz; i++) gid[tax[node[i].len]--] = i;
dp2[1] = 1;
for(int i=1; i<=sz; i++) {
int u = gid[i];
ans = (ans+dp1[u])%mod;
// printf("%d %d %d\n", u, dp1[u], dp2[u]);
for(int j=(u==1 ? 1:0); j<=9; j++) {
if(node[u].next[j+1] == 0) continue;
int nst = node[u].next[j+1];
dp1[nst] = (dp1[nst] + dp1[u]*10 + j*dp2[u])%mod;
dp2[nst] = (dp2[nst] + dp2[u])%mod;
}
}
printf("%d\n", ans);
}
} sam;
char s[maxn], t[maxn]; int main() {
while(~scanf("%d", &T)) {
mes(s, 0);
n = 0;
while(T--) {
scanf("%s", t+1);
int tlen = strlen(t+1);
for(int i=1; i<=tlen; i++) {
s[++n] = t[i]-'0'+1;
}
s[++n] = 11;
}
sam.init();
for(int i=1; i<=n; i++) {
sam.insert(s[i]);
}
sam.solve();
}
return 0;
}

str2int HDU - 4436 (后缀自动机)的更多相关文章

  1. str2int HDU - 4436 后缀自动机求子串信息

    题意: 给出 n 个串,求出这 n 个串所有子串代表的数字的和. 题解; 首先可以把这些串构建后缀自动机(sam.last=1就好了), 因为后缀自动机上从 root走到的任意节点都是一个子串,所有可 ...

  2. HDU 4436 (后缀自动机)

    HDU 4436 str2int Problem : 给若干个数字串,询问这些串的所有本质不同的子串转换成数字之后的和. Solution : 首先将所有串丢进一个后缀自动机.由于这道题询问的是不同的 ...

  3. HDU 5442 后缀自动机(从环字符串选定一个位置 , 时针或顺时针走一遍,希望得到字典序最大)

    http://acm.hdu.edu.cn/showproblem.php?pid=5442 题目大意: 给定一个字符串,可理解成环,然后选定一位置,逆时针或顺时针走一遍,希望得到字典序最大,如果同样 ...

  4. HDU 4622 (后缀自动机)

    HDU 4622 Reincarnation Problem : 给一个串S(n <= 2000), 有Q个询问(q <= 10000),每次询问一个区间内本质不同的串的个数. Solut ...

  5. HDU 4416 (后缀自动机)

    HDU 4416 Good Article Good sentence Problem : 给一个串S,和一些串T,询问S中有多少个子串没有在T中出现. Solution :首先对所有的T串建立后缀自 ...

  6. HDU 5442 后缀自动机+kmp

    题目大意: 给定一个字符串,可理解成环,然后选定一位置,逆时针或顺时针走一遍,希望得到字典序最大,如果同样大,希望找到起始位置最小的,如果还相同,就默认顺时针 比赛一直因为处理最小位置出错,一结束就想 ...

  7. hdu 6208(后缀自动机、或者AC自动机

    题意:给你n个字符串,问你是否存在一个字符串可以从中找到其他n-1个字符串. 思路:其实很简单,找到最长的那个字符串对他进行匹配,看是否能匹配到n-1个字符串. 可以用AC自动机或者后缀自动机做,但是 ...

  8. Boring counting HDU - 3518 后缀自动机

    题意: 对于给出的字符串S, 长度不超过1000, 求其中本质不同的子串的数量, 这些子串满足在字符串S中出现了至少不重合的2次 题解: 将串放入后缀自动机中然后求出每一个节点对应的子串为后缀的子串出 ...

  9. Alice's Classified Message HDU - 5558 后缀自动机求某个后缀出现的最早位置

    题意: 给定一个长度不超过 10W 的只包含小写字母的字符串,从下标 0 到 n−1.从下标 0 开始操作, 每次对于下标 pos查找下标 pos 开始的子串中最长的在其他地方出现过的长度,其他出现的 ...

随机推荐

  1. 用ab每隔30分钟并发一次休息10分钟

    linux脚本监控程序运行情况(重启程序)主要有两种情况:一种是一个可执行文件:如shell脚本文件:另一种是使用python打开的多个程序.第一种:它的进程名字由路径名字和程序名字组成,比如:我有个 ...

  2. c#创建windows服务(代码方式安装、启动、停止、卸载服务)

    转载于:https://www.cnblogs.com/mq0036/p/7875864.html 一.开发环境 操作系统:Windows 10 X64 开发环境:VS2015 编程语言:C# .NE ...

  3. 排序算法Java代码实现(一)—— 选择排序

    以下几篇随笔都是记录的我实现八大排序的代码,主要是贴出代码吧,讲解什么的都没有,主要是为了方便我自己复习,哈哈,如果看不明白,也不要说我坑哦! 本片分为两部分代码: 常用方法封装 排序算法里需要频繁使 ...

  4. C#控制操控操作多个UVC摄像头设备

    有时,我们需要在C#代码中对多个UVC摄像头进行操作,如何实现呢? 建立基于SharpCamera的项目 首先,请根据之前的一篇博文 点击这里 中的说明,建立基于SharpCamera的摄像头控制项目 ...

  5. 2019 乐游网络java面试笔试题 (含面试题解析)

      本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.乐游网络等公司offer,岗位是Java后端开发,因为发展原因最终选择去了乐游网络,入职一年时间了,也成为了面 ...

  6. Python进阶----pymysql的安装与使用,mysql数据库的备份和恢复,mysql的事务和锁

    Python进阶----pymysql的安装与使用,mysql数据库的备份和恢复,mysql的事务和锁 一丶安装 pip install PyMySQL 二丶pymysql连接数据库 ### 语法: ...

  7. MTSC2019-深圳站 议题征集

    议题截止时间 11月初 议题投递地址 topic@testerhome.com   臣一路走来,没有敌人,看见的都是朋友和师长 —司马懿 关于中国移动互联网测试大会 MTSC 大会(中国移动互联网测试 ...

  8. 8.Javascript-map、reduce、filter 等高阶函数

    高阶函数 高阶函数是对其他函数进行操作的函数,可以将它们作为参数或通过返回它们.简单来说,高阶函数是一个函数,它接收函数作为参数或将函数作为输出返回. 例如Array.prototype.map,Ar ...

  9. Csharp 基础笔记知识点整理

    /* * @version: V.1.0.0.1 * @Author: fenggang * @Date: 2019-06-16 21:26:59 * @LastEditors: fenggang * ...

  10. 你可能还不知道的关于JavaScript类型的细节?

    类型 七种类型: Undefined Null Boolean String Number Symbol Object Undefined.Null 阅读问题:为什么有的编程规范要求使用void 0 ...