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 ...
随机推荐
- hdu3038How Many Answers Are Wrong(带权并查集)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3038 题解转载自:https://www.cnblogs.com/liyinggang/p/53270 ...
- js常见的排序算法
最近面试可能会问这些 1,插入排序 function sort(elements){ var res =[elements[0]]; for (var i = 0; i < elements.l ...
- 用foobar进行码率转换 适用与sacd-r转成低码率
之前下载了不少高清音频,有黑胶转录的也有母带文件.这些高清音频大都是24bit,采样率96khz或者88.2khz或者更高.而我想将部分精品专辑刻录成cd.首先我需要将这些文件转换为16bit,44. ...
- poj2689 Prime Distance
题意:求[a, b]之间差最大/小的相邻素数. 0 < a, b < 2^32, 0 < b - a <= 1e6 首先发现a,b很大,以至于无法求出素数来. 然后就考虑退而求 ...
- luogu2643 聪聪可可
题目链接 题意 其实转化之后的题意就是求出树上有多少条路径长度是3的倍数.求答案的时候只要将这个数字除以总路径数量就行了. 思路 考虑点分治.对于当前子树,分别求出出树中每个点到根的路径长度对\(3\ ...
- [luogu3834][可持久化线段树 1(主席树)]
题目链接 思路 裸的主席树.查询的时候,通过相减求出区间内左子树中数的个数a.然后判断要查找的k是否比这个z要大.如果比这个值大,那么就去右子树中查找第k - z大,否则去左子树中查找第k大. 代码 ...
- (转)C++ 值传递、指针传递、引用传递详解
一直以来对函数的值传递引用传递理解很模糊,这篇文章可以说是给自己扫盲了. 值传递:实参不会发生改变,是因为形参传递的是不是实参的源地址(形参和实参地址不一样).不影响实参 指针传递:本质也是值传递,只 ...
- vue学习(3)
回顾昨天内容 1.let和const 2.模板字符串 `` 插变量${变量名} 3.箭头函数 function(){} == ()=>{} 1.this的指向问题 2.arguments不能使用 ...
- TODO maven学习笔记
maven是什么? 我的体会 我理解得maven就是一个构建工具,可以做一些项目得整合操作,我们把一些常见得操作,封装在maven里面,并给它命名成 clean,test,compile,这些步骤都是 ...
- (find) nyoj5-Binary String Matching
5-Binary String Matching 内存限制:64MB 时间限制:3000ms 特判: No通过数:232 提交数:458 难度:3 题目描述: Given two strings A ...