非常奇妙的倍增题

题目描述

知名科学家小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

最新文章

  1. linux 下 sudo 指令不需要输入密码的配置
  2. placeholder 使用
  3. [Virtualization][SDN] 讲的很好的SDN软件定义网络视频课程
  4. [Js]瀑布流
  5. Linux共享内存
  6. oracle删除用户所有表
  7. 使用Flex图表组件
  8. Maven命令行创建web项目,并部署到jobss当中(解决No plugin found for prefix &#39;jboss-as&#39; in the current project and in the plugin groups [org.apache.maven.plugins,问题)
  9. db_link
  10. (转)linux下如何批量杀JAVA进程或某个进程方法
  11. 2019/2/11 LinuxRPM包管理
  12. 云服务器上mysql的配置
  13. [hihocoder1509][异或排序]
  14. 在try-catch机制优化IO流关闭时,OutputStreamWriter 数据流被截断
  15. 【转载整理】mysql权限分配详解
  16. Docker 下 mysql 简单的 主从复制实现
  17. Ucloud云主机无法yum安装处理办法
  18. Windows下MySQL免安装版的安装、卸载
  19. 20135239 益西拉姆 linux内核分析 读书笔记之第四章
  20. 修改选择排序 Exercise07_20

热门文章

  1. load View 流程 程序启动流程
  2. JDK1.7 和 jetty配置教程
  3. JSON脱敏
  4. H - String painter
  5. hdu 2108 Shape of HDU(判定是不是凸多边形)
  6. E: 软件包 ffmpeg 没有可供安装的候选者
  7. vue初级学习--使用 vue-resource 请求数据
  8. 遍历list集合的三种方式
  9. 初始Mybatis,好累,自己感觉自己快坚持不了了
  10. java动态代理使用详解