Description

  

  给你一个长度不超过100的字符串。一共进行\(N\)次操作,第\(i\)次操作是将当前字符串复制一份接到后面,并将新的一份循环移位\(k_i\)(\(1 \le k_i \le 100\))次。给出\(M\)(\(1 \le M \le 100000\))个询问,每次询问所有操作完成之后,\([l,r]\)中,某个字母出现了多少次。其中\(1 \le l \le r \le 10^{18}\)。

  

  

  

Solution

  

   我开场就写了2个小时的暴力分治,并惊喜地发现单个询问可以秒出。结果一组询问需要0.01s,拿到了40分的好成绩。

  

   首先\(N\)只有约前60项是有意义的,因此总操作数大约是60次。

  

   这种字符串变换题目要重点观察变换前和变换后是否有一大块一大块是相等的。比如某次操作前,字符串是\(S\),\(A\)和\(B\)是\(S\)的两块(即\(S=AB\))其中B的长度恰好是这次操作的偏移值。那么操作完之后,字符串的变化如下:

\[AB\rightarrow AB\;BA
\]

   既然只有60次操作,而每次操作的\(B\)的长度不超过100,我们完全可以算出每次操作的\(B\)串。即枚举每个字符,反向模拟这个字符是怎么从原串变换来的,即可在一个\(\log\)的时间确定每个字符是什么。

  

   将询问查分,则我们要求\([1,n]\)中有多少个\(c\)字符。

  

   考虑从最后一次操作开始递归向前计算(其实应该是:最早的一次操作,满足操作后串长不小于\(n\))。

  

   如果\(n\)落在左边的\(AB\)内:那么直接递归前一次操作,返回其答案。

  

   如果\(n\)落在右边的\(B\)内:左半边\(AB\)的答案显然,就是原串中这个字符的数量乘上左半边有多少个原串。对于右边部分,我们预处理出每次操作中\(B\)的字母前缀和,\(O(1)\)可询问\(B\)前缀字母数量。两者加起来就是答案。

  

   如果\(n\)落在右边的\(A\)内:\(ABB\)的答案可以用上一个情况的思路直接算,而最右边的\(A\)的答案,其实就是最左边的\(A\)的对应位置的答案。和第一种情况一样,我们递归前一次操作即可知道这部分的答案。

  

   我们发现总分治递归层数不会超过有效操作次数。因此这题可以在\(\mathcal O(M\log 10^{18})\)内解决。

  

  

  

Code

  

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
namespace IO{
const int S=20000005;
char buffer[S];
int pos;
void Load(){
pos=0;
fread(buffer,1,S,stdin);
}
char getChar(){
char res=buffer[pos++];
if(pos>=S)
Load();
return res;
}
ll getLong(){
ll x=0,f=1;
char c=getChar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getChar();}
while('0'<=c&&c<='9'){x=x*10+c-'0';c=getChar();}
return x*f;
}
int getStr(char *str){
int len=0;
for(char c=getChar();'a'<=c&&c<='z';c=getChar())
str[len++]=c;
return len;
}
}
using IO::getLong;
using IO::getStr;
const int N=110,B=70,C=26;
const ll UP=2e18;
char str[N];
int slen;
int n,m,off[100005];
int pre[N][C],f[B][N][C];
void readData(){
slen=IO::getStr(str+1);
n=getLong(); m=getLong();
for(int i=1;i<=n;i++)
off[i]=getLong();
}
inline ll get_len(int bit){
return 1ll*slen*(1ll<<bit);
}
char get_char(int bit,ll x){
if(bit==0)
return str[x];
ll mid=get_len(bit-1);
if(x<=mid)
return get_char(bit-1,x);
ll cut=mid+off[bit];
if(x<=cut)
return get_char(bit-1,mid-(cut-x));
else
return get_char(bit-1,x-cut);
}
void precount(){
for(int i=1;i<=slen;i++){
for(int j=0;j<26;j++)
pre[i][j]=pre[i-1][j];
pre[i][str[i]-'a']++;
}
for(int i=1;get_len(i)<UP;i++){
ll mid=get_len(i-1);
off[i]%=mid;
for(int j=1;j<=off[i];j++){
for(int k=0;k<26;k++)
f[i][j][k]+=f[i][j-1][k];
char c=get_char(i-1,mid-off[i]+j);
f[i][j][c-'a']++;
}
}
}
ll solve(int bit,ll n,int c){
if(bit==0)
return pre[n][c];
ll mid=get_len(bit-1),cut=mid+off[bit];
if(n<=mid)
return solve(bit-1,n,c);
if(n<=cut)
return 1ll*pre[slen][c]*(1ll<<(bit-1))+f[bit][n-mid][c];
else
return 1ll*pre[slen][c]*(1ll<<(bit-1))+f[bit][cut-mid][c]+solve(bit-1,n-cut,c);
}
ll calc(ll n,char c){
if(!n)
return 0;
int bit;
for(bit=0;get_len(bit)<n;bit++);
return solve(bit,n,c-'a');
}
void answerQuery(){
ll l,r;
char c[2];
for(int i=1;i<=m;i++){
l=getLong(); r=getLong(); getStr(c);
printf("%lld\n",calc(r,c[0])-calc(l-1,c[0]));
}
}
int main(){
IO::Load();
readData();
precount();
answerQuery();
return 0;
}

CJB的大作的更多相关文章

  1. NOIp2018模拟赛三十五

    两道大数据结构把我砸懵 成绩:未提交 Orz xfz两道正解 A:[BZOJ4049][CREC2014B]mountainous landscape B:CJB的大作(CF改编题)

  2. 转载部长一篇大作:常用排序算法之JavaScript实现

    转载部长一篇大作:常用排序算法之JavaScript实现 注:本文是转载实验室同门王部长的大作,找实习找工作在即,本文颇有用处!原文出处:http://www.cnblogs.com/ywang172 ...

  3. cjb

    输入216.194.70.6 ,进入到是cjb.net的主页,并不是shell.cjb.net ,进入主页后点击shell,就进不去了 分析:shell.cjb.net被DNS污染了 解法:hosts ...

  4. Bishop的大作《模式识别与机器学习》Ready to read!

    久仰Bishop的大作“Pattern Recognition and Machine Learning”已久,在我的硬盘里已经驻扎一年有余,怎奈惧其页数浩瀚,始终未敢入手.近日看文献,屡屡引用之.不 ...

  5. 当今游戏大作share的特性大盘点

    极品游戏制作时的考虑要素大盘点 不知不觉入坑Steam已近4年,虽然说Steam的毒性让很多人走向一条不归路,但是想我这样即使"中毒"还是很快乐很感恩的.那么本期文章就谈谈我对其中 ...

  6. 深入Guerrilla Games解密次世代开山大作《杀戮地带暗影坠落》(The technology of Killzone Shadow Fall)

    文章摘要:这几天终于有时间,把全文翻译完了,自己感觉不是太满意,不过大家能看懂就好,就当一个学习的机会.整篇文章通过SONY第一方游戏工作室Guerrilla Games主创的语录,为我们展现了次世代 ...

  7. 关于Delphi中的字符串的浅析(瓢虫大作,里面有内存错误的举例)

    关于Delphi中的字符串的浅析 只是浅浅的解析下,让大家可以快速的理解字符串. 其中的所有代码均在Delphi7下测试通过. Delphi 4,5,6,7中有字符串类型包括了: 短字符串(Short ...

  8. 採訪The Molasses Flood:BioShock Infinite 游戏之后又一大作

    Xsolla有幸与Flame in the Flood游戏的开发人员之中的一个-----Forrest Dowling进行了採訪,Flame in the Flood这款非常棒的游戏在Kickstar ...

  9. 5月,专用程序猿的经典大作——APUE

    五一小长假刚刚过去,收回我们游走的心.開始你们的读书旅程吧! 本期特别推荐 经典UNIX著作最新版. 20多年来,这本书帮助几代程序猿写出强大.高性能.可靠的代码. 第3版依据当今主流系统进行更新,更 ...

随机推荐

  1. .net 设置Webbowser 版本

    .net 里的Webbowser控件默认情况是用IE7来渲染 可修改注册表试用是最新的版本来渲染: using System; using System.Collections.Generic; us ...

  2. SQLAlchemy 与 fask-SQLAlchemy 中的多表查询例子

    我们知道,<学生.课程.选课>,是一个典型的多对多关系. 现分别用 SQLAlchemy 与 fask-SQLAlchemy 实现. 声明:本人实测通过. 使用 SQLAlchemy fr ...

  3. winform和wpf如何实现鼠标穿透的效果

    先看一下鼠标穿透的效果: 可以看到Form1这个程序虽然遮在了桌面的上面,但是我们还可以在窗体上点击桌面上的必应词典和网易邮箱大师,好像这个叫“Form1”的窗口被“穿透”一样. winform版本: ...

  4. windows下如何查看进程、端口占用、杀死进程教程

    一. 查看所有进程占用的端口 在开始-运行-cmd,输入:netstat –ano 可以查看所有进程 二.查看占用指定端口的程序 当你在用tomcat发布程序时,经常会遇到端口被占用的情况,我们想知道 ...

  5. Java 多线程(五)之 synchronized 的使用

    目录 1 线程安全 2 互斥锁 3 内置锁 synchronized 3.1 普通同步方法,锁是当前实例对象(this) 3.1.1 验证普通方法中的锁的对象是同一个. 3.1.2 验证不同的对象普通 ...

  6. 新的旅程:NodeJS - 环境篇

    用ASP.NET MVC好多年了,还记得当初为MVC所倡导的"DRY"理念所感染,为Razor的简单而震撼.随着MVC的成熟反而让我觉得似乎渐渐地走入了微软营造的一种高技术的牢笼. ...

  7. 使用ClosedXML,读取到空行

    最近项目中使用了ClosedXML.dll来处理Excel,在读取Excel的时候,用workSheet.Rows()获取Excel行数,默认读取Excel最大行数1048576 所以为了读取到不是空 ...

  8. 用 IIS 搭建 mercurial server

    mercurial server 对于代码管理工具,更多的人可能对 Git 更熟悉一些(Git太火了).其实另外一款分布式代码管理工具也被广泛的使用,它就是 mercurial.当多人协作时最好能够通 ...

  9. 【原】python3.7 无法pip安装提示ssl错误解决方案

    问题 pip is configured with locations that require TLS/SSL, however the ssl module in Python is not av ...

  10. CommandoVM-虚拟机映像文件 | VM打开直接用

    呵呵!自从火眼发布了这个CommandoVM,想必大家应该都挺激动,然而实际操作一下,基本炸裂-- 因为并没有给类似于kali这种直接安装的现成镜像,而是要通过github的脚本去完全网络安装 实际操 ...