Loj #3055. 「HNOI2019」JOJO

时间:2021-12-03 09:47:06

Loj #3055. 「HNOI2019」JOJO

JOJO 的奇幻冒险是一部非常火的漫画。漫画中的男主角经常喜欢连续喊很多的「欧拉」或者「木大」。

为了防止字太多挡住漫画内容,现在打算在新的漫画中用 \(x\) 欧拉或者 \(x\) 木大表示有 \(x\) 个欧拉或者木大。

为了简化内容我们现在用字母表示喊出的话。

我们用数字和字母来表示一个串,例如:2 a 3 b 表示的串就是 aabbb

一开始漫画中什么话都没有,接下来你需要依次实现 \(n\) 个操作,总共只有 \(2\) 种操作:

  • 第一种:1 x c:在当前漫画中加入 \(x\) 个 \(c\),表示在当前串末尾加入 \(x\) 个 \(c\) 字符。保证当前串是空串或者串尾字符不是 \(c\);
  • 第二种:2 x:觉得漫画没画好,将漫画还原到第 \(x\) 次操作以后的样子,表示将串复原到第 \(x\) 次操作后的样子,如果 \(x=0\) 则是将串变成空串。如果当前串是 bbaabbb,第 \(4\) 次操作后串是 bb,则 2 4 会使 bbaabbb 变成 bb,保证 \(x\) 小于当前操作数。

众所周知空条承太郎十分聪明,现在迪奥已经被打败了,他开始考虑自己的漫画中的一些问题:

对于一个串的每个前缀 \(A\),都有一个最长的比它短的前缀 \(B\) 与前缀 \(A\) 的一个后缀匹配,设这个最长的前缀 \(B\) 的长度为 \(L\)。\(L\) 为 \(0\) 时意味着 \(B\) 是一个空串。

每一次操作后,你都需要将当前的串的所有前缀的 \(L\) 求和并对 \(998244353\) 取模输出告诉空条承太郎,好和他的白金之星算出的答案对比。比如 bbaaabba 的 \(L\) 分别是 \(0, 1, 0, 0, 0, 1, 2, 3\),所以对于这个串的答案就是 \(7\)。

输入格式

第一行包括一个正整数 \(n\),表示操作数量。

接下来 \(n\) 行每行包含一个操作,操作格式如题目描述所示,例如:

  • 1 x c
  • 2 x

保证数据合法。

输出格式

仅包含 \(n\) 行,第 \(i\) 行一个整数,表示 \(i\) 个操作之后串的答案。

数据范围与提示

\(20\%\) 的数据满足 \(n\le 300\),对于每个 \(1\) 操作中的 \(x\le 300\);

另有 \(30\%\) 的数据满足 \(n\le 10^5\),且对于每个 \(1\) 操作中的 \(x=1\);

另有 \(30\%\) 的数据满足 \(n\le 10^5\),且不含 \(2\) 操作;

\(100\%\) 的数据满足 \(n\le 10^5\),且每个 \(1\) 操作中的 \(x\le 10^4\)。

我们用一个节点代表一次加入的一段连续字符。

假设每个加入的节点的父亲就是上一次加入的节点,这样我们就得到了一颗树。

计算答案的时候就在树上\(dfs\)并用可回退数据结构维护一下就行了。为了避免跳\(next\)的操作,我们可以用可持久化线段树维护儿子集合。

不过我计算答案也是暴力跳的。我想了个解决方案就是对每个\(next\)的链的每种字符维护一个栈就行了。

代码:

#include<bits/stdc++.h>
#define ll long long
#define N 100005 using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;} const ll mod=998244353;
int n; const int maxx=1e4+1;
const int lx=1,rx=27*(1e4);
int rt[N];
vector<int>e[N];
int first[N]; int tag[N*70],ls[N*70],rs[N*70];
int tot; void Insert(int &v,int old,int lx,int rx,int p,int ID) {
v=++tot;
ls[v]=ls[old];
rs[v]=rs[old];
if(lx==rx) {
tag[v]=ID;
return ;
}
int mid=lx+rx>>1;
if(p<=mid) Insert(ls[v],ls[old],lx,mid,p,ID);
else Insert(rs[v],rs[old],mid+1,rx,p,ID);
} int query(int v,int lx,int rx,int p) {
if(lx>p||rx<p) return 0;
if(!v) return 0;
if(lx==rx) return tag[v];
int mid=lx+rx>>1;
if(p<=mid) return query(ls[v],lx,mid,p);
else return query(rs[v],mid+1,rx,p);
} int fail[N];
int now=0;
int back[N],len[N],pre[N],col[N];
int sn[N]; ll Sum(ll n) {return n*(n+1)/2%mod;} int cal(int v,int u) {
int f=fail[v];
ll ans=0;
int lst=0;
do {
if(col[sn[f]]==col[u]) {
if(!f) {
if(min(len[sn[f]]-1,len[u])>lst) (ans+=Sum(min(len[sn[f]]-1,len[u]))-Sum(lst)+mod)%=mod;
if(len[sn[f]]<=len[u]) (ans+=1ll*len[sn[f]]*(len[u]-max(lst,len[sn[f]]-1)))%=mod;
} else if(len[sn[f]]>lst) {
(ans+=1ll*(min(len[u],len[sn[f]])-lst)*pre[f])%=mod;
lst=min(len[u],len[sn[f]]);
}
}
f=fail[f];
} while(f!=-1&&lst<len[u]); ans+=Sum(lst);
return ans;
} int cal2(int f,int u,int lim) {
while(f!=-1) {
if(col[sn[f]]==col[u]&&len[sn[f]]>=lim) return pre[f]+lim;
f=fail[f];
}
f=0;
return 0;
} int ans[N];
int SN0;
void dfs1(int v) {
for(int i=0;i<e[v].size();i++) {
int to=e[v][i];
int lst=query(rt[v],lx,rx,len[to]+col[to]*maxx);
fail[to]=lst;
Insert(rt[v],rt[v],lx,rx,len[to]+col[to]*maxx,to);
if(!lst&&SN0&&col[SN0]==col[to]&&len[SN0]<=len[to]) fail[to]=SN0;
rt[to]=rt[fail[to]];
if(!v) SN0=to;
dfs1(to);
if(!v) SN0=0;
Insert(rt[v],rt[v],lx,rx,len[to]+col[to]*maxx,lst);
}
} void dfs2(int v,ll tot) {
ans[v]=tot;
ll now;
for(int i=0;i<e[v].size();i++) {
int to=e[v][i];
if(!v) now=(tot+Sum(len[to]-1))%mod;
else {
now=tot;
(now+=cal(v,to))%=mod;
}
sn[v]=to;
dfs2(to,now);
}
} int FA[N];
int qid[N]; int main() {
// freopen("jojo10.in","r",stdin);
// freopen("my.out","w",stdout);
n=Get();
int lst=0;
int op,x;
char c;
int SN0=0;
fail[0]=-1;
first[0]=0;
for(int i=1;i<=n;i++) {
op=Get();
if(op==1) {
lst=back[i-1];
rt[lst]=first[lst];
x=Get();
while(c=getchar(),!isalpha(c));
len[++now]=x;
pre[now]=pre[lst]+len[now];
col[now]=c-'a';
qid[i]=now;
e[lst].push_back(now);
FA[now]=lst;
back[i]=now;
} else {
x=Get();
back[i]=back[x];
qid[i]=qid[x];
}
}
dfs1(0);
dfs2(0,0);
for(int i=1;i<=n;i++) cout<<ans[qid[i]]<<"\n";
return 0;
}

Loj #3055. 「HNOI2019」JOJO的更多相关文章

  1. LOJ 3055 「HNOI2019」JOJO—— kmp自动机&plus;主席树

    题目:https://loj.ac/problem/3055 先写了暴力.本来想的是 n<=300 的那个在树上暴力维护好整个字符串, x=1 的那个用主席树维护好字符串和 nxt 数组.但 x ...

  2. Loj &num;3059&period; 「HNOI2019」序列

    Loj #3059. 「HNOI2019」序列 给定一个长度为 \(n\) 的序列 \(A_1, \ldots , A_n\),以及 \(m\) 个操作,每个操作将一个 \(A_i\) 修改为 \(k ...

  3. Loj &num;3056&period; 「HNOI2019」多边形

    Loj #3056. 「HNOI2019」多边形 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时针方向标号依次为 \(1,2,3, \ldots , n\).最开 ...

  4. Loj 3058&period; 「HNOI2019」白兔之舞

    Loj 3058. 「HNOI2019」白兔之舞 题目描述 有一张顶点数为 \((L+1)\times n\) 的有向图.这张图的每个顶点由一个二元组 \((u,v)\) 表示 \((0\le u\l ...

  5. Loj &num;3057&period; 「HNOI2019」校园旅行

    Loj #3057. 「HNOI2019」校园旅行 某学校的每个建筑都有一个独特的编号.一天你在校园里无聊,决定在校园内随意地漫步. 你已经在校园里呆过一段时间,对校园内每个建筑的编号非常熟悉,于是你 ...

  6. 【loj - 3055】「HNOI2019」JOJO

    目录 description solution accepted code details description JOJO 的奇幻冒险是一部非常火的漫画.漫画中的男主角经常喜欢连续喊很多的「欧拉」或 ...

  7. LOJ 3059 「HNOI2019」序列——贪心与前后缀的思路&plus;线段树上二分

    题目:https://loj.ac/problem/3059 一段 A 选一个 B 的话, B 是这段 A 的平均值.因为 \( \sum (A_i-B)^2 = \sum A_i^2 - 2*B \ ...

  8. LOJ 3057 「HNOI2019」校园旅行——BFS&plus;图等价转化

    题目:https://loj.ac/problem/3057 想令 b[ i ][ j ] 表示两点是否可行,从可行的点对扩展.但不知道顺序,所以写了卡时间做数次 m2 迭代的算法,就是每次遍历所有不 ...

  9. LOJ 3056 「HNOI2019」多边形——模型转化&plus;树形DP

    题目:https://loj.ac/problem/3056 只会写暴搜.用哈希记忆化之类的. #include<cstdio> #include<cstring> #incl ...

随机推荐

  1. &lpar;C&num;&rpar; 判断相等?

    值类型直接用 == 号判断就好. 但是对于引用类型,需要实现IComparable 接口,或者重写 Equal 方法,来实现自己的比较目的. 因为对于引用类型,==号比较的是入口地址,对于同一个cla ...

  2. Oozie JMS通知消息实现--根据作业ID来过滤消息

    一,介绍 本文使用Oozie的消息通知功能,并根据JMS规范中的消息选择器(Selector)实现 根据作业的ID来过滤消息. 首先搭建好JMS Provider(ActiveMQ) ,并进行相关配置 ...

  3. ios开发笔记

    @IBDesignable  可在第二视图中实时预览 @IBInspectable 可编辑属性

  4. Linux学习之traceroute命令

    通过traceroute我们可以知道信息从你的计算机到互联网另一端的主机是走的什么路径.当然每次数据包由某一同样的出发点(source)到达某一同样的目的地(destination)走的路径可能会不一 ...

  5. 使用node-livereload自动刷新页面

    1. 安装node 2. 安装python 3. 安装connect, serve-static和node-livereload (以下都假设命令行当前目录为e:\WebSite) e:\WebSit ...

  6. 微信公众号开发——关于&OpenCurlyDoubleQuote;WeixinJSBridge&period;call&lpar;&&num;39&semi;closeWindow&&num;39&semi;&rpar;&semi;”无效的问题

    最近在做微信公众号的开发,再做一个jsp的用户绑定页面,设置了一个timestamp,想实现的是当链接超时时alert一个窗口提示然后关闭网页窗口 但是呢,在jsp页面内直接 out.print(&q ...

  7. 关于flying框架

    开发10多年了,开发过程中遇到的最大的问题: ①项目的代码越来越多了,越来越复杂了,而客户的需求,你还不得不往里面加入新代码. ②开发了很多项目,每次复用时却只能把代码copy来copy去,然后调试. ...

  8. SQL Server的case when用法

    1.简单sql一例 SELECT top 10 CASE WHEN IDENTITY_ID='1' THEN '管理员' WHEN IDENTITY_ID='5' THEN '学生' ELSE '无' ...

  9. sklearn&period;linear&lowbar;model&period;LogisticRegression参数说明

    目录 sklearn.linear_model.LogisticRegression sklearn.linear_model.LogisticRegressionCV sklearn.linear_ ...

  10. C入门程序整体框架图

    0.1:概述, 从头开始介绍一门编程语言总是显得很困难,因为有许多的细节还没有介绍,很难让读者在大脑中形成一幅完整的图, 所以起步时以一个列程序向学折介绍大体的C,试图使大家对C有一个整体大概 影响. ...