[NOI2016]优秀的拆分
https://www.lydsy.com/JudgeOnline/problem.php?id=4650
题解
如果我们能够统计出一个数组a,一个数组b,a[i]表示以i为结尾的AA串个数,b[i]表示以i开头的AA串个数,我们就可以O(n)的统计答案了。
我们开看这么一个算法。
先枚举A的长度len,然后按照A的长度把序列分成很多段,每段有一个代表点即这一段的第一个点。
然后枚举所有代表点l,再枚举r=l+len,求一下(1,l)和(1,r)的最长公共后缀,(l,n)和(r,n)的最长公共前缀。

就像这样,但如果是上述情况的话,是无法拼成AA串的,因为蓝色和橙色并没有完全覆盖中间的红色段。

如果是这样的话就可以了,有多少个呢?蓝色和橙色组成的大的线段的左右端点就是第一条线段的左端点和第二条线段的右端点,这条线段可以在中间任意滑动。

然后就可以差分统计答案了。

这种算法相当于利用两个A的开头不会在同一个块内出现,只会在相邻两个块出现的性质做的。

注意,在求公共前后缀时要和和len取min,否则就会算多。

代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define N 30002
using namespace std;
int n,m,y[N],tong[N],T;
long long tag1[N],tag2[N],ans;
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
struct suffixarray{
int rnk[N],sa[N],height[N],p[][N];
char s[N];
inline void qsort(){
for(int i=;i<=n;++i)tong[rnk[i]]++;
for(int i=;i<=m;++i)tong[i]+=tong[i-];
for(int i=n;i>=;--i)sa[tong[rnk[y[i]]]--]=y[i];
for(int i=;i<=m;++i)tong[i]=;
}
inline void SA(){
m=;
for(int i=;i<=n;++i)rnk[i]=s[i],y[i]=i;
qsort();
for(int w=,p=;p<n;m=p,w<<=){
p=;
for(int i=n-w+;i<=n;++i)y[++p]=i;
for(int i=;i<=n;++i)if(sa[i]>w)y[++p]=sa[i]-w;
qsort();swap(rnk,y);
rnk[sa[]]=p=;
for(int i=;i<=n;++i)
rnk[sa[i]]=((y[sa[i]]==y[sa[i-]])&&(y[sa[i]+w]==y[sa[i-]+w]))?p:++p;
}
for(int i=;i<=n;++i){
if(rnk[i]==)continue;
int j=max(,height[rnk[i-]]-);
while(s[i+j]==s[sa[rnk[i]-]+j])++j;
height[rnk[i]]=j;
p[][rnk[i]]=j;
}
for(int i=;(<<i)<=n;++i)
for(int j=;j+(<<i)-<=n;++j)
p[i][j]=min(p[i-][j],p[i-][j+(<<i-)]);
}
inline int query(int l,int r){
if(l>r)swap(l,r);l++;
if(l>r)return 2e9;
int lo=log2(r-l+);
return min(p[lo][l],p[lo][r-(<<lo)+]);
}
inline void clear(){
// memset(p,0,sizeof(p));
memset(height,,sizeof(height));
memset(s,,sizeof(s));
memset(rnk,,sizeof(rnk));
memset(sa,,sizeof(sa));
}
}z,f;
inline void init(){
memset(y,,sizeof(y));
ans=;
memset(tag1,,sizeof(tag1));memset(tag2,,sizeof(tag2));
}
int main(){
T=rd();
while(T--){
z.clear();f.clear();init();
scanf("%s",z.s+);n=strlen(z.s+);
for(int i=;i<=n;++i)f.s[i]=z.s[n-i+];f.s[n+]=z.s[n+]=;
f.SA();z.SA();
for(int i=;i<=n/;++i)
for(int j=;j+i<=n;j+=i){
int l=j,r=j+i;
int lcp=min(i,z.query(z.rnk[l],z.rnk[r])),lcs=min(i,f.query(f.rnk[n-l+],f.rnk[n-r+]));
if(lcp+lcs>=i+){
tag1[l-lcs+(i<<)]++;tag1[r+lcp]--;
tag2[l-lcs+]++;tag2[r+lcp-(i<<)+]--;
}
//cout<<l<<" "<<r<<" "<<lcp<<" "<<lcs<<endl;
}
for(int i=;i<=n;++i)tag1[i]+=tag1[i-],tag2[i]+=tag2[i-];
for(int i=;i<=n;++i)ans+=tag1[i-]*tag2[i];
cout<<ans<<endl;
} return ;
}

股市的预测

墨墨的妈妈热爱炒股,她要求墨墨为她编写一个软件,预测某只股票未来的走势。股票折线图是研究股票的必备工
具,它通过一张时间与股票的价位的函数图像清晰地展示了股票的走势情况。经过长时间的观测,墨墨发现很多股
票都有如下的规律:之前的走势很可能在短时间内重现!如图可以看到这只股票A部分的股价和C部分的股价的走势
如出一辙。通过这个观测,墨墨认为他可能找到了一个预测股票未来走势的方法。进一步的研究可是难住了墨墨,
他本想试图统计B部分的长度与发生这种情况的概率关系,不过由于数据量过于庞大,依赖人脑的力量难以完成,
于是墨墨找到了善于编程的你,请你帮他找一找给定重现的间隔(B部分的长度),有多少个时间段满足首尾部分
的走势完全相同呢?当然,首尾部分的长度不能为零。
题解
我们把序列差分之后,相当于是求形如ABA的串,这和上一题就差不多了。
每次取得l=i,r=i+m+len。然后就和上一题一样了。
每次新增加的答案为max(0,公共前缀+公共后缀-len)
代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 50002
using namespace std;
int n,m,y[N],ans,tong[N],M,b[N],c[N];
inline int rd(){
int x=;char c=getchar();bool f=;
while(!isdigit(c)){if(c=='-')f=;c=getchar();}
while(isdigit(c)){x=(x<<)+(x<<)+(c^);c=getchar();}
return f?-x:x;
}
struct suffixarray{
int rnk[N],sa[N],a[N],height[N],p[][N];
inline void qsort(){
for(int i=;i<=m;++i)tong[i]=;
for(int i=;i<=n;++i)tong[rnk[i]]++;
for(int i=;i<=m;++i)tong[i]+=tong[i-];
for(int i=n;i>=;--i)sa[tong[rnk[y[i]]]--]=y[i];
}
inline void SA(){
m=;
for(int i=;i<=n;++i)rnk[i]=a[i],y[i]=i;
qsort();
for(int w=,p=;p<n;m=p,w<<=){
p=;
for(int i=n-w+;i<=n;++i)y[++p]=i;
for(int i=;i<=n;++i)if(sa[i]>w)y[++p]=sa[i]-w;
qsort();swap(rnk,y);
rnk[sa[]]=p=;
for(int i=;i<=n;++i)
rnk[sa[i]]=((y[sa[i]]==y[sa[i-]])&&(y[sa[i]+w]==y[sa[i-]+w]))?p:++p;
}
for(int i=;i<=n;++i){
if(rnk[i]==)continue;
int j=max(,height[rnk[i-]]-);
while(a[i+j]==a[sa[rnk[i]-]+j])++j;
height[rnk[i]]=j;
p[][rnk[i]]=j;
}
for(int i=;(<<i)<=n;++i)
for(int j=;j+(<<i)-<=n;++j)
p[i][j]=min(p[i-][j],p[i-][j+(<<i-)]);
}
inline int query(int l,int r){
if(l>r)swap(l,r);l++;
if(l>r)return 2e9;
int lo=log2(r-l+);
return min(p[lo][l],p[lo][r-(<<lo)+]);
}
}z,f;
int main(){
n=rd();M=rd();
for(int i=;i<=n;++i)b[i]=rd();
for(int i=n-;i>=;--i)z.a[i]=b[i+]-b[i],c[i]=z.a[i];n--;
sort(c+,c+n+);int tt=unique(c+,c+n+)-c-;
for(int i=;i<=n;++i)z.a[i]=lower_bound(c+,c+tt+,z.a[i])-c;
for(int i=;i<=n;++i)f.a[n-i+]=z.a[i];
z.SA();f.SA();
for(int i=;i<=(n-M)/;++i){
for(int j=;j<=n&&j+i+M<=n;j+=i){
int l=j,r=i+j+M;
int lcp=min(i,z.query(z.rnk[l],z.rnk[r])),lcs=min(i,f.query(f.rnk[n-l+],f.rnk[n-r+]));
int x=lcs+lcp-i;
if(x>)ans+=x;
}
}
cout<<ans;
return ;
}

[NOI2016]优秀的拆分&&BZOJ2119股市的预测的更多相关文章

  1. bzoj 4650(洛谷 1117) [Noi2016]优秀的拆分——枚举长度的关键点+后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4650 https://www.luogu.org/problemnew/show/P1117 ...

  2. luogu1117 [NOI2016]优秀的拆分

    luogu1117 [NOI2016]优秀的拆分 https://www.luogu.org/problemnew/show/P1117 后缀数组我忘了. 此题哈希可解决95分(= =) 设\(l_i ...

  3. 【BZOJ4560】[NOI2016]优秀的拆分

    [BZOJ4560][NOI2016]优秀的拆分 题面 bzoj 洛谷 题解 考虑一个形如\(AABB\)的串是由两个形如\(AA\)的串拼起来的 那么我们设 \(f[i]\):以位置\(i\)为结尾 ...

  4. [UOJ#219][BZOJ4650][Noi2016]优秀的拆分

    [UOJ#219][BZOJ4650][Noi2016]优秀的拆分 试题描述 如果一个字符串可以被拆分为 AABBAABB 的形式,其中 A 和 B 是任意非空字符串,则我们称该字符串的这种拆分是优秀 ...

  5. [NOI2016]优秀的拆分(SA数组)

    [NOI2016]优秀的拆分 题目描述 如果一个字符串可以被拆分为 \(AABB\) 的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串 \(aabaaba ...

  6. 题解-NOI2016 优秀的拆分

    NOI2016 优秀的拆分 \(T\) 组测试数据.求字符串 \(s\) 的所有子串拆成 \(AABB\) 形式的方案总和. 数据范围:\(1\le T\le 10\),\(1\le n\le 3\c ...

  7. [NOI2016]优秀的拆分 后缀数组

    题面:洛谷 题解: 因为对于原串的每个长度不一定等于len的拆分而言,如果合法,它将只会被对应的子串统计贡献. 所以子串这个限制相当于是没有的. 所以我们只需要对于每个位置i求出f[i]表示以i为开头 ...

  8. [BZOJ]4650: [Noi2016]优秀的拆分

    Time Limit: 30 Sec  Memory Limit: 512 MB Description 如果一个字符串可以被拆分为 AABBAABB 的形式,其中 AA 和 BB 是任意非空字符串, ...

  9. [Noi2016]优秀的拆分

    来自F allDream的博客,未经允许,请勿转载,谢谢. 如果一个字符串可以被拆分为 AABB 的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串 aab ...

随机推荐

  1. E: 无法打开锁文件 /var/lib/dpkg/lock-frontend - open (13: 权限不够)E: 无法获取 dpkg 前端锁 (/var/lib/dpkg/lock-frontend),请查看您是否正以 root 用户运行?

    一.解决方案 修改root密码,以root身份安装 sudo pwdroot root  # 输入新密码即可

  2. PHP常见错误汇总

    日常开发和调试的时候,经常会遇到一些错误,光怪陆离的不知所以,所以,特此将错误汇总一下,借鉴!!! 1. 原因分析:  一般可能是该文件出现了问题,检查一下代码和格式,是否出现开始的地方出现了空格,或 ...

  3. python自动化常见问题汇总

           1.如何提高selenium脚本的执行速度? Selenium脚本的执行速度受多方面因素的影响,如网速,操作步骤的繁琐程度,页面加载的速度,以及我们在脚本中设置的等待时间,运行脚本的线程 ...

  4. Oracle RMAN备份与还原注意事项

    1 备份文件管理 如果要删除之前的备份,不要手动去目录下删除,应该在rman命令模式下使用删除命令,否则虽然在磁盘上把物理备份文件删除了,但是使用备份查看命令会一直看到已经删除的备份文件 list b ...

  5. js 判断一个字符在字符串中出现的次数

    <script type="text/javascript"> var s='djh.doiwe.esd.d.ddd0sdd.d.'; var n=(s.split(' ...

  6. hive权限配置

    基于CDH5.x的Hive权限配置 1.打开权限控制,默认是没有限制的 set hive.security.authorization.enabled=true; 2.配置默认权限 hive.secu ...

  7. jQuery 事件 - triggerHandler() 方法

    定义和用法 triggerHandler() 方法触发被选元素的指定事件类型.但不会执行浏览器默认动作,也不会产生事件冒泡. triggerHandler() 方法与 trigger() 方法类似.不 ...

  8. VSCode 汉化

    https://jingyan.baidu.com/article/7e44095377c9d12fc1e2ef5b.html

  9. prometheus和metrucs-server (k8s监控)

    资源指标:metrucs-server 自定义指标:prometheus, k8s-prometheus-adapter(转换prometheus数据的格式) 新一代架构: 核心指标流水线:由kube ...

  10. 如何在集合中巧用Where来查找相关元素

    在我们的项目中我们经常会查找一些集合中的重要元素,当然我们可以使用常规的foreach循环和if语句来查询,但是我们要学会使用System.Linq命名空间下面的静态类Enumerable下面的静态方 ...