luogu 3538/bzoj 2795 Poi2008 哈希+质数结论
题意:给定一个子串,询问一些子区间内的最短循环节(循环节是越短条件约束越多)
开始一看那就哈希处理然后暴力枚举循环节,然后按照循环节长度暴力向后比较,本地测试40,洛谷60
#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i=x;i<=y;i++)
using namespace std;
const int N=;
typedef unsigned long long ull; char s[N];int q;
ull p[N],sum[N],b; inline ull get(int l,int r){
return sum[r]-sum[l-]*p[r-l+];} int main(){
// freopen("2795.in","r",stdin);
// freopen("2795.out","w",stdout);
int n;scanf("%d",&n);
scanf("%s",s+); p[]=;b=; rep(i,,n) p[i]=p[i-]*b;
rep(i,,n) sum[i]=sum[i-]*b+(s[i]-'a'+); scanf("%d",&q);
rep(i,,q){
int l,r;scanf("%d%d",&l,&r);
int len=r-l+;
rep(j,,len){
if(len%j) continue;
int FG=;ull s=get(l,l+j-);
int k=(int)s;
for(int k=l+j;k<=r;k+=j)
if(s!=get(k,k+j-)){FG=;break;}
if(FG){printf("%d\n",j);break;}
}
}
return ;
}
再然后就是小作修改,在比较时计算新串哈希值,和原串比较,复杂度还是qn 2,不过本地47,洛谷60没变
#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i=x;i<=y;i++)
using namespace std;
const int N=;
typedef unsigned long long ull; char s[N];int q;
ull p[N],sum[N],b; inline ull get(int l,int r){
return sum[r]-sum[l-]*p[r-l+];} int main(){
// freopen("2795.in","r",stdin);
// freopen("2795.out","w",stdout);
int n;scanf("%d",&n);
scanf("%s",s+); p[]=;b=; rep(i,,n) p[i]=p[i-]*b;
rep(i,,n) sum[i]=sum[i-]*b+(s[i]-'a'+); scanf("%d",&q);
rep(i,,q){
int l,r;scanf("%d%d",&l,&r);
int len=r-l+,FG=;
ull s=get(l,r); rep(j,,len){
if(len%j) continue;
int cnt=len/j;
ull sk=get(l,l+j-),ss=; rep(k,,cnt)
ss+=sk*p[(cnt-k)*j];
if(ss==s) {printf("%d\n",j);FG=;break;}
}
if(FG) printf("0\n");
}
return ;
}
翻看题解之后明白了性质,总结如下
1.循环节是长度的约数,循环节越短限制条件越多
2.若n是循环节,k*n也是循环节
3.循环节判断方法,设循环节长度为k,[l,r-k]==[l+k,r]即相同
4.不断枚举质因数,实质上等同于枚举其约数,约数就是由质因数组成
5.一个合数,在欧拉筛过程中被筛掉时实际上由较大的质因数筛掉,所以若取被谁筛掉时应是较大质因数(说不定就是最大呢,可是我也不知道啊)
经过简单修改得到了在洛谷和bz上A掉的代码,但是本地测试78,还是有测试点没过,啊啊啊本地数据真的玄学
#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i=x;i<=y;i++)
using namespace std;
const int N=;
typedef unsigned long long ull; char s[N];int q,cnt,yueshu[N];
ull p[N],sum[N],b; inline ull get(int l,int r){//写成函数,真香
return sum[r]-sum[l-]*p[r-l+];}
int v[N],prime[N>>],nxt[N];
bool check(int l1,int r1,int l2,int r2){
if(get(l1,r1)==get(l2,r2)) return ;return ;}
void init(int n){
v[]=;
for(int i=;i<=n;i++){
if(!v[i]) prime[++cnt]=i,nxt[i]=i;
for(int j=;j<=cnt&&i*prime[j]<=n;j++){
v[i*prime[j]]=;
nxt[i*prime[j]]=prime[j];//nxt数组存储某个约数的质因数(应该是比较大的那个吧,菜鸡也只是猜的)
if(i%prime[j]==) break;}
}
}
int main(){
// freopen("2795.in","r",stdin);
// freopen("2795.out","w",stdout);
int n;scanf("%d",&n);
scanf("%s",s+);init(n); p[]=;b=; rep(i,,n) p[i]=p[i-]*b;
rep(i,,n) sum[i]=sum[i-]*b+(s[i]-'a'+); scanf("%d",&q);
rep(i,,q){
int l,r;scanf("%d%d",&l,&r);
int len=r-l+,idx=;
//nxt数组存储质因数
//yueshu数组内存储的是可以认为是未来的循环节个数
//e.g:10 5 2 存在多个质数
while(len!=){
yueshu[++idx]=nxt[len];//提前将可能除到1的质因数按照大小搞出来,这样就可以1个循环搞定
len=len/nxt[len];}
len=r-l+;
for(int j=;j<=idx;j++){
int k=len/yueshu[j];//得到的k才是循环节长度
if(check(l,r-k,l+k,r)) len=k;}
printf("%d\n",len);}
return ;
}
核心操作:判断长度的约数是不是循环节,删除后再继续判断
本来需要多层循环,但由于质因数的存在使得其实就是不断往下判断即可
啊啊啊,哈希kmpac自动机trie树继续刷题啊啊啊啊
luogu 3538/bzoj 2795 Poi2008 哈希+质数结论的更多相关文章
- Luogu 3810 & BZOJ 3262 陌上花开/三维偏序 | CDQ分治
Luogu 3810 & BZOJ 3263 陌上花开/三维偏序 | CDQ分治 题面 \(n\)个元素,每个元素有三个值:\(a_i\), \(b_i\) 和 \(c_i\).定义一个元素的 ...
- Bzoj 1131[POI2008]STA-Station (树形DP)
Bzoj 1131[POI2008]STA-Station (树形DP) 状态: 设\(f[i]\)为以\(i\)为根的深度之和,然后考虑从他父亲转移. 发现儿子的深度及其自己的深度\(-1\) 其余 ...
- bzoj 2795 [Poi2012]A Horrible Poem hash+线性筛
题目大意 bzoj 2795 给出一个由小写英文字母组成的字符串S,再给出q个询问,要求回答S某个子串的最短循环节. 如果字符串B是字符串A的循环节,那么A可以由B重复若干次得到. n<=500 ...
- Luogu 3369 / BZOJ 3224 - 普通平衡树 - [无旋Treap]
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=3224 https://www.luogu.org/problemnew/show/P3 ...
- Luogu P1198 BZOJ 1012 最大数 (线段树)
手动博客搬家: 本文发表于20170821 14:32:05, 原地址https://blog.csdn.net/suncongbo/article/details/77449455 URL: (Lu ...
- BZOJ 1113: [Poi2008]海报PLA
1113: [Poi2008]海报PLA Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1025 Solved: 679[Submit][Statu ...
- BZOJ 1116: [POI2008]CLO
1116: [POI2008]CLO Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 922 Solved: 514[Submit][Status][ ...
- BZOJ 1112: [POI2008]砖块Klo
1112: [POI2008]砖块Klo Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1736 Solved: 606[Submit][Statu ...
- BZOJ 1124: [POI2008]枪战Maf
1124: [POI2008]枪战Maf Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 617 Solved: 236[Submit][Status ...
随机推荐
- JAVA多线程之volatile 与 synchronized 的比较
一,volatile关键字的可见性 要想理解volatile关键字,得先了解下JAVA的内存模型,Java内存模型的抽象示意图如下: 从图中可以看出: ①每个线程都有一个自己的本地内存空间--线程栈空 ...
- 分布式链路跟踪 Sleuth 与 Zipkin【Finchley 版】
原创: dqqzj SpringForAll社区 今天 Spring Cloud Sleuth Span是基本的工作单位. 例如,发送 RPC是一个新的跨度,就像向RPC发送响应一样. 跨度由跨度唯一 ...
- 每天一个Linux命令 (转)
一. 文件目录操作命令: 1.每天一个linux命令(1):ls命令 2.每天一个linux命令(2):cd命令 3.每天一个linux命令(3):pwd命令 4.每天一个linux命令(4):mk ...
- 第三十一节,目标检测算法之 Faster R-CNN算法详解
Ren, Shaoqing, et al. “Faster R-CNN: Towards real-time object detection with region proposal network ...
- org.apache.poi 读取数字问题
默认呢,POI读取单元格内容为数字的话,自动搞成Dubbo类型的,比如这样: String value1 = row.getCell(0).getNumericCellValue()+"&q ...
- Vuex异步请求数据通过computed计算属性值
问题描述: 使用Vuex管理数据时,在组件内使用$emit分发事件后,获取回来的数据要自动更新到该组件内,需要使用computed来计算更新. 一开始尝试使用赋值给data的方法,后来发现重新发起aj ...
- IntelliJ IDEA载入JDBC驱动包
1.下载zip格式的驱动包:https://dev.mysql.com/downloads/connector/j/ 2.解压zip,放到任意位置.其中的mysql-connector-java.ja ...
- FFT的一种迭代实现
struct Complex { double x,y; Complex(double x1=0.0 ,double y1=0.0) { x=x1; y=y1; } Complex operator ...
- (链表) leetcode 21. Merge Two Sorted Lists
Merge two sorted linked lists and return it as a new list. The new list should be made by splicing t ...
- 字节输入流 FileInputStream
字节输入流 InputStream : 方法介绍: read(); 读取下一个字节 返回-1读取文件结束 close(); 复制文件 将数据aaa.txt复制到d盘 字节输入流读---->字节输 ...