@description@

给定一个大小为 G 的字符集,并给定一个长度为 N 的字符串 A。

求最短不是 A 的子序列的字符串的长度为 L,以及长度为 L 的不是 A 的子序列的字符串数量 X。

1 <= N <= 2,000,000; 1 <= G <= 10^9。

原题戳这里

@solution@

暴力做法?考虑将 A 的所有子序列塞进 trie 里面,则 trie 中出度不为 G 的点后面加字符一定不是 A 的子序列。

注意到这是一个有限状态自动机,可以识别 A 的所有子序列(oi-wiki 上好像把它叫作序列自动机?)。

考虑简化这个自动机。记结点 i 能识别的字符串为以 A[i] 为结尾的,且在 A[1...i-1] 中没有出现的子序列。

假设 i 前面第一个与它相同的位置在 lst[i],则 lst[i] 之前的连向 i 就会重复,而 [lst[i], i-1] 连向 i 恰好是所有可能的子序列。

注意到这是一个区间的连边形式,我们可以线段树优化连边。

(还有另一种理解方式:第 i 个点的字符 j 转移边,连向 i 之后第一个 j 的出现位置。这个解释可以在 oi-wiki 中看到。)

注意一个结点可以表示多个字符串,而有用的只有这个结点能够表示的最短的字符串。

我们处理出 len[i] 表示以 i 结尾的最短子序列长度,并记 cnt[i] 表示最短子序列的种类数。

连完边后一样看出度是否为 G。

记 oud[i] 表示 i 的出度,则 i 对 len[i] + 1 长度有着 (G - oud[i])*cnt[i] 的贡献。

实际操作并不需要真的连边,只需要用线段树维护上面三种信息。

@accepted code@

#include <unordered_map>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
class ShortestMissingSubsequences{
private :
#define MAXN 2000000
#define MOD 1000000007
typedef pair<int, int> pii;
typedef long long ll; unordered_map<int, int>mp;
int A[MAXN + 5], lst[MAXN + 5];
int len[MAXN + 5], tot[MAXN + 5], cnt[MAXN + 5]; #define lch (x<<1)
#define rch (x<<1|1)
pii tag[4*MAXN + 5]; int nw[4*MAXN + 5];
pii merge(pii a, pii b) {
pii c; c.first = min(a.first, b.first);
if( c.first == a.first ) c.second = (c.second + a.second) % MOD;
if( c.first == b.first ) c.second = (c.second + b.second) % MOD;
return c;
}
void pushup(int x) {tag[x] = merge(tag[lch], tag[rch]);}
pii get(int x, int l, int r, int ql, int qr) {
if( ql <= l && r <= qr ) {
nw[x]++;
return tag[x];
}
if( ql > r || qr < l )
return make_pair(MAXN + 5, 0);
int m = (l + r) >> 1;
return merge(get(lch, l, m, ql, qr), get(rch, m + 1, r, ql, qr));
}
void update(int x, int l, int r, int p) {
if( l == r ) {
tag[x] = make_pair(len[p], tot[p]);
return ;
}
int m = (l + r) >> 1;
if( p <= m ) update(lch, l, m, p);
else update(rch, m + 1, r, p);
pushup(x);
}
void push(int x, int l, int r, int d) {
d += nw[x];
if( l == r ) {
cnt[l] = d;
return ;
}
int m = (l + r) >> 1;
push(lch, l, m, d), push(rch, m + 1, r, d);
}
public :
vector<int>count(int G, int N, vector<int>Aprefix) {
int M = Aprefix.size();
for(int i=0;i<M;i++) A[i+1] = Aprefix[i];
ll state = A[M];
for(int i=M+1;i<=N;i++) {
state = (state * 1103515245LL + 12345) % (1LL<<31);
A[i] = state % G;
}
for(int i=1;i<=N;i++)
lst[i] = mp[A[i]], mp[A[i]] = i;
len[0] = 0, tot[0] = 1, update(1, 0, N, 0);
for(int i=1;i<=N;i++) {
pii p = get(1, 0, N, lst[i], i - 1);
len[i] = p.first + 1, tot[i] = p.second;
update(1, 0, N, i);
}
push(1, 0, N, 0);
int mn = MAXN + 5;
for(int i=0;i<=N;i++)
if( cnt[i] != G )
mn = min(mn, len[i]);
vector<int>ans; ans.push_back(mn + 1);
int x = 0;
for(int i=0;i<=N;i++)
if( len[i] == mn )
x = (x + 1LL*tot[i]*(G - cnt[i])%MOD) % MOD;
ans.push_back(x);
return ans;
}
};

@details@

被小小地卡了一下常。。。

@topcoder - SRM766R1 D1L3@ ShortestMissingSubsequences的更多相关文章

  1. Topcoder SRM570 D1L3 CurvyonRails

    几个样例: 5 5wCCwwwCC....w......www..wReturns: 0 3 3C.w....C.Returns: 1 21 20CC..CCCw.CwC..CC.w.CC.CCCwC ...

  2. @topcoder - 2013TCO3A D1L3@ TrickyInequality

    目录 @description@ @accepted code@ @accepted code@ @details@ @description@ 现有不等式组: \[\begin{cases} x_1 ...

  3. TopCoder kawigiEdit插件配置

    kawigiEdit插件可以提高 TopCoder编译,提交效率,可以管理保存每次SRM的代码. kawigiEdit下载地址:http://code.google.com/p/kawigiedit/ ...

  4. 记第一次TopCoder, 练习SRM 583 div2 250

    今天第一次做topcoder,没有比赛,所以找的最新一期的SRM练习,做了第一道题. 题目大意是说 给一个数字字符串,任意交换两位,使数字变为最小,不能有前导0. 看到题目以后,先想到的找规律,发现要 ...

  5. TopCoder比赛总结表

    TopCoder                        250                              500                                 ...

  6. Topcoder几例C++字符串应用

    本文写于9月初,是利用Topcoder准备应聘时的机试环节临时补习的C++的一部分内容.签约之后,没有再进行练习,此文暂告一段落. 换句话说,就是本文太监了,一直做草稿看着别扭,删掉又觉得可惜,索性发 ...

  7. TopCoder

    在TopCoder下载好luncher,网址:https://www.topcoder.com/community/competitive%20programming/ 选择launch web ar ...

  8. TopCoder SRM 596 DIV 1 250

    body { font-family: Monospaced; font-size: 12pt } pre { font-family: Monospaced; font-size: 12pt } P ...

  9. 求拓扑排序的数量,例题 topcoder srm 654 div2 500

    周赛时遇到的一道比较有意思的题目: Problem Statement      There are N rooms in Maki's new house. The rooms are number ...

随机推荐

  1. oauth2使用心得-----基本概念以及认证服务器搭建

    应用场景 我们假设你有一个“云笔记”产品,并提供了“云笔记服务”和“云相册服务”,此时用户需要在不同的设备(PC.Android.iPhone.TV.Watch)上去访问这些“资源”(笔记,图片) 那 ...

  2. DAO设计模式总结

    1.DAO(Data Access Object,数据访问对象),主要的功能是用于进行数据操作的,在程序的标准开发框架中属于数据层的操作. 数据开发结构流程: 资源层是数据库的操作层,里面可以进行各种 ...

  3. mysql建表设置格式

    建表时必须设置字段编码格式为COLLATE utf8_bin,表示查询时该字段内容区分大小写,如果不需要区分大小写,可以设置为COLLATE utf8_ genera_ci,表示忽略大小写

  4. Vuejs实战项目四:权限校验

    路由跳转参考文档:https://router.vuejs.org/zh/guide/advanced/navigation-guards.html 在/src下创建permission.js进行权限 ...

  5. Octave 软件的安装

    每次安装软件都感觉是一种心痛的历程.下载安装,然后就跳出一堆的错误,之后就各种百度求救,然后就搞了大半天,有时候还搞不定. 最后,搞定的时候发现,原来这么简单,结果时间就这样浪费了,所以还是把这个过程 ...

  6. 跟我一起做一个vue的小项目(十一)

    接下来我们进行的是详情页动态路由及banner布局 先看页面的效果 下面是代码部分 <template> <div> <div class="banner&qu ...

  7. TZ_14_Zuul网关

    1.spring-cloud的微服务大致是 2.zuul是 Netflix开源的微服务网关, 它可以和 Eureka. Ribbon. Hystrix等组件配合使用.zul的核心是一系列的过滤器,这些 ...

  8. Yii 网站上线不需手动配置

    参考: http://www.cnblogs.com/x3d/p/php_auto_prepend_file.html

  9. Hackerrank--Prime Sum

    题目链接 The problem is quite simple. You're given a number N and a positive integer K. Tell if N can be ...

  10. spring cloud深入学习(四)-----eureka源码解析、ribbon解析、声明式调用feign

    基本概念 1.Registe 一一服务注册当eureka Client向Eureka Server注册时,Eureka Client提供自身的元数据,比如IP地址.端口.运行状况指标的Uri.主页地址 ...