【倍增】7.11fusion
非常奇妙的倍增题
题目描述
知名科学家小A在2118年在计算机上实现了模拟聚变的过程。我们将她研究的过程简化。核子共有26种,可以用a到z共26个字母表示。核子聚变的过程可以用一个字符串描述。按照顺序从左到右的顺序,假如有两个相同核子相邻,两个核子就会相互吸引发生聚变生成一个序号+1的核子,特殊的,两个z核子相邻会湮灭没有新的核子生成。每当两个核子聚变时,就需要重新从左到右重复找到两个相邻的相同核子直到不存在为止。比如zyzzy->zyy->zz->小A为了做出足够有效的实验,每次会从一个字符串中选定一个子串操作。她想要知道每次实验这个子串中的核子能否最终全部湮灭。
输入格式
第一行一个只有小写字母的字符串。第二行一个数nn表示询问次数接下来nn行每行两个正整数li,rili,ri表示询问区间
输出格式
对每次询问输出一行Yes或No表示答案
样例输入
yzyyyzyzyyyz
8
1 6
7 12
1 12
6 11
1 1
1 3
4 9
3 8
样例输出
Yes
Yes
Yes
Yes
No
No
No
No
数据规模与约定
L表示字符串长度对于30%的数据满足L<=100
对于60%的数据满足L<=3000,n<=3000
另存在20%数据满足字符串中只存在y,z
对于100%的数据,L<=500000,n<=1000000
题目分析
摘要
第一眼看上去是个数据结构题……但是很明显这题的状态数非常多,并且区间信息也难以合并,所以所有基于序列长度的维护都是要挂的。
这题妙就是在于它用倍增维护基于结果的区间信息。(听上去很高端的样子实际上是不难理解的)
暴力做法
暴力的O(n^2)做法可以得60pts。具体实现可以用栈也可以用链表。
大概就是这个样子。
#include<bits/stdc++.h>
const int maxn = ;
const long long numz = ; long long f[maxn];
int pre[maxn],nxt[maxn],head,tail;
char ch[maxn];
int n,m,a[maxn],tot; int lowbit(int x){return x&-x;}
void add(int x, long long c){for (; x<=n; x+=lowbit(x)) f[x]+=c;}
long long query(int x)
{
long long ret = ;
for (; x; x-=lowbit(x)) ret += f[x];
return ret;
}
bool check(int l, int r)
{
tot = n, head = l, tail = r;
for (int i=l; i<=r; i++)
pre[i] = i-, nxt[i] = i+;
pre[l] = -, nxt[r] = -;
for (;;)
{
bool fl = ;
if (head==-) return ;
if (nxt[head]==-) return ;
for (int now=head; nxt[now]!=-; now=nxt[now])
if (a[now]==a[nxt[now]]){
fl = ;
if (a[now]==numz){
int ss = pre[now], tt = nxt[nxt[now]];
if (head==now){
head = tt;
if (tt==-) return ;
pre[tt] = -;
}
else{
nxt[ss] = tt;
if (tt!=-) pre[tt] = ss;
}
}else{
a[++tot] = a[now]*;
int ss = pre[now], tt = nxt[nxt[now]];
if (head==now){
head = tot;
if (tt==-) return ;
pre[tt] = tot, nxt[tot] = tt;
}
else{
nxt[ss] = tot, pre[tot] = ss, nxt[tot] = tt;
if (tt!=-) pre[tt] = tot;
}
}
break;
}
if (!fl) return ;
}
}
int main()
{
freopen("fusion.in","r",stdin);
freopen("fusion.out","w",stdout);
scanf("%s",ch+);
n = strlen(ch+);
for (int i=; i<=n; i++)
a[i] = <<(ch[i]-'a'), add(i, 1ll*a[i]);
scanf("%d",&m);
for (int i=; i<=m; i++)
{
int l,r;
scanf("%d%d",&l,&r);
if ((query(r)-query(l-))%numz==){
if (check(l, r)) puts("Yes");
else puts("No");
}else puts("No");
}
return ;
}
链表模拟
跳一跳?
用nxt[i]表示以i为左端点第一次消完的区间右端点。那么只要预处理出这个nxt[]就可以做到快速查询了————然而查询时也有可能被例如zzzzzzzzz...的数据卡飞,不过对于随机数据已经做得够好了。
先不管zzzzz...的情况,来考虑如何处理nxt[]。
用$t_{i,char}$表示i位置往后第一次遇到char字符的位置,这个是用来处理“聚变”的过程。那么显然这个可以用倍增维护。
处理出$t_{i,char}$之后,nxt[i]就等于$t_{i,z+1}$,这里我们把z聚变后也看做一个虚拟的字符。
再来一个倍增!
既然一维的$nxt[]$会被卡挂,那么同时处理消去好几次后的$nxt[]$(等同于跳了多次)呢?那么nxt[i][j]就表示以i开头消去j次后的位置。
重要的细节
这里有一组数据:xzzxyz
如果只有上面的操作,答案将会是No,因为计算出的结果里第一个x与第二个x是不能接触的。
所以要根据算出的$t_{i,z+1}$更新所有的$t_{i,j}$
#include<bits/stdc++.h>
#pragma GCC optimize(2)
const int maxn = ;
const int maxLog = ;
const long long numz = ; int n,m,s[maxn];
int t[maxn][],nxt[maxn][];
char ch[maxn]; bool check(int l, int r)
{
for (int i=maxLog; i>=; i--)
if (nxt[l][i]==r+) return ;
else if (nxt[l][i]<=r) l = nxt[l][i];
return ;
}
void init()
{
register int i,j;
for (i=; i<=n+; i++)
{
for (j=; j<=; j++) t[i][j] = n+;
for (j=; j<=maxLog; j++) nxt[i][j] = n+;
}
for (i=n; i>=; i--)
{
t[i][s[i]] = i+;
for (j=s[i]+; j<=; j++) t[i][j] = t[t[i][j-]][j-];
nxt[i][] = t[i][];
for (j=; j<=; j++)
if (t[i][j]==n+)
t[i][j] = t[nxt[i][]][j];
for (j=; j<=maxLog; j++) nxt[i][j] = nxt[nxt[i][j-]][j-];
}
}
int main()
{
register int i,l,r;
freopen("fusion.in","r",stdin);
freopen("fusion.out","w",stdout);
scanf("%s",ch+);
n = strlen(ch+);
for (i=; i<=n; i++) s[i] = ch[i]-'a';
scanf("%d",&m);
init();
for (i=; i<=m; i++)
{
scanf("%d%d",&l,&r);
if (check(l, r)) puts("Yes");
else puts("No");
}
return ;
}
END
【倍增】7.11fusion的更多相关文章
- 后缀数组的倍增算法(Prefix Doubling)
后缀数组的倍增算法(Prefix Doubling) 文本内容除特殊注明外,均在知识共享署名-非商业性使用-相同方式共享 3.0协议下提供,附加条款亦可能应用. 最近在自学习BWT算法(Burrows ...
- [板子]倍增LCA
倍增LCA板子,没有压行,可读性应该还可以.转载请随意. #include <cstdio> #include <cstring> #include <algorithm ...
- 在线倍增法求LCA专题
1.cojs 186. [USACO Oct08] 牧场旅行 ★★ 输入文件:pwalk.in 输出文件:pwalk.out 简单对比时间限制:1 s 内存限制:128 MB n个被自 ...
- LCA 倍增||树链剖分
方法1:倍增 1498ms #include <iostream> #include <cstdio> #include <algorithm> #include ...
- Codevs 2370 小机房的树 LCA 树上倍增
题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子, ...
- Uva 11354 LCA 倍增祖先
题目链接:https://vjudge.net/contest/144221#problem/B 题意:找一条从 s 到 t 的路,使得瓶颈路最小. 点的数目是10^4,如果向之前的方案求 maxc ...
- 后缀数组:倍增法和DC3的简单理解
一些定义:设字符串S的长度为n,S[0~n-1]. 子串:设0<=i<=j<=n-1,那么由S的第i到第j个字符组成的串为它的子串S[i,j]. 后缀:设0<=i<=n- ...
- Codeforces Round #381 (Div. 2) 复习倍增//
刷了这套题 感触良多 我想 感觉上的差一点就是差很多吧 . 每次都差一点 就是差很多了... 不能气馁..要更加努力去填补那一点点. 老天不是在造物弄人,而是希望你用更好的自己去迎接自己. A. ...
- 2016弱校联盟十一专场10.5---As Easy As Possible(倍增)
题目链接 https://acm.bnu.edu.cn/v3/contest_show.php?cid=8506#problem/A problem description As we know, t ...
随机推荐
- C#字符串判断
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using Sy ...
- linux ping
ping [ -d] [ -D ] [ -n ] [ -q ] [ -r] [ -v] [ -R ] [ -a addr_family ] [ -c Count ] [ -w timeout ...
- [題解](最小生成樹)luogu_P1265
首先考虑最小生成树的模型,唯一不同的是第二种情形. 即“三个或三个以上的城市申请修建的公路成环” 考虑该情形,因为修路的申请是申请离它最近的城市,所以上述条件实质上为 “存在三个或三个以上的城市,他们 ...
- TopCoder9915(期望dp)
1.还是逆向. 2.状态是还剩红i黑j张时的期望,这样从0,0往R,B推.注意因为是逆着的,所以到了某一步发现期望为负时直接f[i][j]归零,意义是这之后(在递推中算是这之前)的都不摸了,到这就停( ...
- GYM 101889E(dp)
dp[i][j][k]表示第i位填数字k时,与后面的相连模数为j时,后面的数字最小填多少. 测得我提心吊胆还以为复杂度高了,结果出来46ms还是cf评测姬强啊. #pragma comment(lin ...
- shell脚本由基础变量及特殊变量($@、$*、$#等)到实战。
一.shell脚本建立: shell脚本通常是在编辑器(如vi/vim)中编写,也可以在命令行中直接执行: 1.脚本开头: 规范的脚本第一行需要指出有哪个程序(解释器)来执行脚本中的内容,在L ...
- awk一些简单命令
最简单地说, AWK 是一种用于处理文本的编程语言工具.AWK 在很多方面类似于 shell 编程语言,尽管 AWK 具有完全属于其本身的语法. 尽管操作可能会很复杂,但命令的语法始终是: awk ' ...
- simhash与重复信息识别
在工作学习中,我往往感叹数学奇迹般的解决一些貌似不可能完成的任务,并且十分希望将这种喜悦分享给大家,就好比说:“老婆,出来看上帝”…… 随着信息爆炸时代的来临,互联网上充斥着着大量的近重复信息,有效地 ...
- vue http请求 vue-resource使用方法
1.安装vue-resource扩展: npm install vue-resource 2.在main.js中引入 import http from 'vue-resource' 3.使用方法 // ...
- Sonar静态代码扫描环境搭建(Windows10)
一.环境配置: 1.jdk安装及配置 2.MySQL数据库安装----直接调用服务器院端的MySQL数据库,在此基础上创建新的数据库sonar. 数据库的配置如下: 3.sonar官网下载sonar ...