UVA1673

这道题可以用广义后缀自动机,不过陈锋老师给我们讲了一个巧妙地方法,使得这道题可以用普通的后缀自动机做。

题目大意

给出NNN个完全由数字组成的字符串。计算将这个NNN的字符串的所有子串转换为整数后先去重再求和的结果,输出其模2012的余数。也就是求其子串的所有本质不同的字符串的和。

预处理

首先,我们可以将NNN个字符串拼接起来,拼接的部位可以用一个特殊的分隔符隔开。比如这里我用 :,因为′:′−′0′=10':'-'0'=10′:′−′0′=10。我们将拼接好的字符串记作SSS,这样问题就转换成求SSS中所有不含分隔符的本质不同的子串的和。对SSS建立后缀自动机。

定义

Cnt[v]Cnt[v]Cnt[v]为从SAMSAMSAM的初始状态到状态vvv中的所有不含分隔符以及前导0的数量(根据题意,前导0去掉后算一个。比如01和1算作同一个子串)。

Sum[v]Sum[v]Sum[v]为从初始状态到状态vvv的所有合法路径形成的数字之和。

转移方程

Cnt[v]=∑u∈FatherOf(v)Cnt[u]Cnt[v]=\sum\limits_{u\in FatherOf(v)}{Cnt[u]}Cnt[v]=u∈FatherOf(v)∑​Cnt[u]即v由u转移而来。而关于合法转移,只要在转移时不向分隔符的方向走子串就不会出现分隔符;只要不再初始状态往0走,就不会出现前导0。

Sum[v]=∑u∈FatherOf(v)Sum[u]∗10+Cnt[u]∗iSum[v]=\sum\limits_{u\in FatherOf(v)}{Sum[u]*10+Cnt[u]*i}Sum[v]=u∈FatherOf(v)∑​Sum[u]∗10+Cnt[u]∗i即当前的状态和为上一状态十进制进一位加上当前选择的路径*对应的合法路径数量。

转移方式

怎样保证方程中的uuu在vvv之前就更新过了呢?不难发现,由于vvv都是由uuu向下走一步得来,因此有:len(u)<len(v)len(u)<len(v)len(u)<len(v)因此我们将所有状态按lenlenlen排个序,从小到大更新即可。本题中的lenlenlen是连续且大量重复的,可以采用计数排序O(N)O(N)O(N)解决,不过快排也够了。

AC代码

#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<map>
using namespace std;
const int MAXN = 120000;
int n;
string S;
struct SAM {
int size, last;
struct Node {
int len = 0, link = 0;
int next[11];
void clear() {
len = link = 0;
memset(next, 0, sizeof(next));
}
} node[MAXN * 2];
void init() {
for (int i = 0; i < size; i++) {
node[i].clear();
}
node[0].link = -1;
size = 1;
last = 0;
}
void insert(char x) {
int ch = x - '0';
int cur = size++;
node[cur].len = node[last].len + 1;
int p = last;
while (p != -1 && !node[p].next[ch]) {
node[p].next[ch] = cur;
p = node[p].link;
}
if (p == -1) {
node[cur].link = 0;
}
else {
int q = node[p].next[ch];
if (node[p].len + 1 == node[q].len) {
node[cur].link = q;
}
else {
int clone = size++;
node[clone] = node[q];
node[clone].len = node[p].len + 1;
while (p != -1 && node[p].next[ch] == q) {
node[p].next[ch] = clone;
p = node[p].link;
}
node[q].link = node[cur].link = clone;
}
}
last = cur;
}
}sam;
int N, Size = 0;
int
Cnt[2 * MAXN],
SUM[2 * MAXN],
Order[2 * MAXN]; bool Input() {
if (scanf("%d", &N) == EOF) {
return false;
}
S.clear();
while (N--) {
string Temp;
cin >> Temp;
S.insert(S.end(), Temp.begin(), Temp.end());
S.push_back(':');
} sam.init();
for (int i = 0; i < S.size(); ++i) {
sam.insert(S[i]);
} return true;
}
constexpr static int mod = 2012;
int DP() {
for (int i = 0; i < sam.size; ++i) {
Order[i] = i;
}
//排序
sort(Order, Order + sam.size, [](const int&Left,const int&Right)->bool {
return sam.node[Left].len < sam.node[Right].len;
}
);
//空串合法
Cnt[0] = 1;
int&& Ans = 0;
for (int i = 0; i < sam.size; ++i) {
const int& u = Order[i];
//如果j是初始状态,就不能往0走,否则就可以,这样就可以去除前导0
for (int j = (u ? 0 : 1); j < 10; ++j) {
const int& v = sam.node[u].next[j];
if (sam.node[v].len) {
Cnt[v] += Cnt[u];
Cnt[v] %= mod;
SUM[v] += SUM[u] * 10 + j * Cnt[u];
SUM[v] %= mod;
}
}
Ans += SUM[u];
Ans %= mod;
}
return Ans;
}
int main() {
while (Input()) {
memset(Cnt, 0x0, sizeof(Cnt));
memset(SUM, 0x0, sizeof(SUM));
printf("%d\n", DP());
}
return 0;
}

数字子串的和 str2int的更多相关文章

  1. C#中的字符串处理——找出最长数字子串

    百度测试部2015年10月份的面试题之——字符串处理,找出最长的子串. 代码如下: private static string SelectNumberFromString(string input) ...

  2. TYVJ P1063 数字串 Label:双指针 线性扫描

    描述 给你一个长度为n的数字串,数字串里会包含1-m这些数字.如果连续的一段数字子串包含了1-m这些数字,则称这个数字字串为NUM串.你的任务是求出长度最短的NUM串是什么,只需要输出这个长度即可.1 ...

  3. 未出现的子串(unapeared)

    未出现的子串(unapeared) 题目描述 有一个长度为n的数字串,其中会出现数字1,2,3,…,q(5≤q≤9).现在的问题是,需要求出一个长度最小的串(出现的数字也是1-q),使得该串不是这个数 ...

  4. 提取字符串中的数字(C语言)

    题目要求 问题描述:给定一个任意字符串,提取出其中所包含的整数. 样例输入:A12 32bc de51f6576g 样例输出:共计 4 个整数:12 32 51 6576 解决方案-指针版本 核心思想 ...

  5. 数字串(codevs 1394)

    题目描述 Description 给你一个长度为n的数字串,数字串里会包含1-m这些数字.如果连续的一段数字子串包含了1-m这些数字,则称这个数字字串为NUM串.你的任务是求出长度最短的NUM串是什么 ...

  6. UnrealScript语言基础

    总体特征 (1)大小写不敏感.关键字.宏.变量名.函数名以及类名不区分大小写:变量名可以与关键字同名 (2)局部变量.成员变量未初始化时,会被编译器初始化 (3)没有全局变量.全局函数,所有东西必须写 ...

  7. Java中将0x开头的十六进制字符串转换成十进制整数

    1.Integer.toString(int i) 由于input(输入数据)是以0x开头的字符串,并不是整型.因而在用 String s = Integer.toString(input); 时用会 ...

  8. AC日记——字符串的展开 openjudge 1.7 35

    35:字符串的展开 总时间限制:  1000ms 内存限制:  65536kB 描述 在初赛普及组的“阅读程序写结果”的问题中,我们曾给出一个字符串展开的例子:如果在输入的字符串中,含有类似于“d-h ...

  9. noi题库(noi.openjudge.cn) 1.7编程基础之字符串T31——T35

    T31 字符串P型编码 描述 给定一个完全由数字字符('0','1','2',-,'9')构成的字符串str,请写出str的p型编码串.例如:字符串122344111可被描述为"1个1.2个 ...

  10. NOI 1.7编程基础之字符串(35题)

    01:统计数字字符个数 查看 提交 统计 提问 总时间限制:  1000ms 内存限制:  65536kB 描述 输入一行字符,统计出其中数字字符的个数. 输入 一行字符串,总长度不超过255. 输出 ...

随机推荐

  1. vim替换查找缩进操作

    1.替换 r(要替换的字符)              将游标所在字母替换为指定字母 R(要替换的字符)             连续替换,直到按下Esc cc          删除整行并进入到插入 ...

  2. printf函数size_t的替换字符串zu

    参考:https://stackoverflow.com/questions/2524611/how-can-one-print-a-size-t-variable-portably-using-th ...

  3. Jmeter固定吞吐量控制器Constant Throughput Timer

    控制请求的TPS,可以使用JMETER的固定吞吐量控制器Constant Throughput Timer Target throughput(in samples per minute):目标吞吐量 ...

  4. ES可视化平台kibana安装和使用

    一.kibana介绍 Kibana是一个针对Elasticsearch的开源分析及可视化平台,用来搜索.查看交互存储在Elasticsearch索引中的数据. 二.kibana安装 1.解压 tar ...

  5. 基于recorder.js H5录音功能

    兼容性 1.Chrome,FF,Edge,QQ,360(注:现有IE和Safari全版本不兼容) 2.其中Chrome47以上以及QQ浏览器强制要求HTTPS的支持 3.请尝试使用FF,Edge,36 ...

  6. dp泄露

    DP泄露 选了三道与RSA的dp泄露有关的题,dp泄露算是比较有辨识度的题型. 目录 DP泄露 原理 ctfshow funnyrsa3 分析 解答 BUUCTF RSA2 分析 解答 [羊城杯 20 ...

  7. 洛谷P4571 [JSOI2009] 瓶子和燃料

    题目 https://www.luogu.com.cn/problem/P4571 思路 首先观察并且简单模拟一下火星人取燃料的过程,发现最终燃料的量一定是他选的k个瓶子容量的线性组合(观察操作3就知 ...

  8. (读书笔记)基于CMMI的软件工程及实训指导(13-16章)

    软件测试 1.定义: 使用人工或自动的手段来运行或测试某个软件系统的过程,其目的在于检验它是否满足规定的需求或弄清预期结果与实际结果之间的差别. 简单来说,软件测试是为了发现程序中的错误而执行的过程. ...

  9. ASP.NET Core中使用日志组件NLog

    上一篇文章描述了如何在ASP.NET Core中使用Log4Net记录日志.本篇将使用另外一个组件NLog在ASP.NET Core中记录日志. 1.引入程序集 NLog.Web.AspNetCore ...

  10. Oracle数据泵恢复用户数据实例

    我们测试环境经常会遇到恢复生产数据的情况,我一般比较习惯使用数据泵来搞,这个具体根据自己的业务形态选择适合自己的方式. 此次我们说的是完全恢复用户数据,具体步骤如下: 1.备份数据 expdp tes ...