A.POJ - 1200 A - Crazy Search
摘要 哈希进制转换
题意
一个字符串分成长度为N的字串。且不同的字符不会超过NC个。问总共有多少个不同的子串
思路
以nc作为进制,把一个子串化为这个进制下的数,再用哈希判断
1 |
|
C.POJ - 2774 Long Long Message
两个字符串最长子串长度
题意
求两个字符串的最长子串长度
题解
二分长度,然后把字符串A的长度mid的哈希值塞入数组,再在字符串B的数组中二分查找长度为mid
复杂度为O(logn×N×logN)
也可以直接用后缀数组的height
1 |
|
D.URAL - 1989 Subpalindromes
线段树/树状数组和哈希应用 判断回文
题意
给定一个字符串(长度<=100000),有两个操作。 1:改变某个字符。 2:判断某个子串是否构成回文串。
题解
把字符串正向,方向插入线段树和树状数组中,然后单点修改,区间查值, 如果正向和方向值一样,那就是回文了
1 | //线段树 |
1 | //树状数组 |
E.CodeForces - 580E Kefa and Watch
线段树+哈希
题意
给你一个长度为n的字符串s,有两种操作:
1 L R C : 把s[l,r]全部变为c;
2 L R d : 询问s[l,r]是否是周期为d的重复串。
题解
n最大为1e5,且m+k最大也为1e5,这就要求操作1和操作2都要采用logn的算法,所以用线段树.
对于更新操作,使用区间更新就可解决。
主要是如何在logn的时间内完成询问操作.
我们采用线段树维护hash值的方法.
结合于类似KMP的性质,我们发现,字符串[l,r]有长度为w的循环节,只需要使得[l,r-w]=[l+w,r]即可。证明过程看这里
这题的hash不同于普通的字符串hash,因为涉及到动态修改,所以需要预先处理出所有的base,在修改的时候直接用.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
using namespace std;
typedef long long ll;
typedef long long ull;
const ll mod=998244353;
const int maxn=1e5+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
int gcd(int a,int b){while(b){int t=a%b;a=b;b=t;}return a;}
int lcm(int a,int b){return a*b/gcd(a,b);}
ull seed=19260817;
//ull seed=10;
ull s[maxn];
ull fs[maxn];
char ss[maxn];
void init(){
s[0]=1;fs[0]=1;
for(int i=1;i<maxn;i++)s[i]=(s[i-1]*seed)%mod;
for(int i=1;i<maxn;i++)fs[i]=(fs[i-1]+s[i])%mod;
/* for(int i=0;i<5;i++){
cout<<i<<"\t"<<s[i]<<"\t"<<fs[i]<<endl;
}*/
}
struct node{
int l,r;
int lazy;
int ok;
ull num;
}my[maxn<<2];
void pushup(int x){
int mid=(my[x].l+my[x].r)>>1;
// printf("x==%d x<<1=%d x<<1|1=%d my[x<<1].num=%llu my[x<<1|1].num=%llu s==%d \n",x,x<<1,x<<1|1,my[x<<1].num,my[(x<<1)|1].num,s[my[x].r-mid]);
my[x].num=(my[x<<1].num*s[my[x].r-mid]+my[(x<<1|1)].num)%mod;
// cout<<"x=="<<x<<" my[x].num"<<my[x].num<<endl;
}
void pushdown(int x){
if(my[x].lazy){
int mid=(my[x].l+my[x].r)>>1;
my[x<<1].lazy=my[(x<<1)|1].lazy=my[x].lazy;
my[x<<1].ok=my[x<<1|1].ok=my[x].ok;
my[x<<1].num=(fs[mid-my[x].l]*my[x].ok)%mod;
my[(x<<1)|1].num=(fs[my[x].r-mid-1]*my[x].ok)%mod;
my[x].lazy=0;
}
}
void build(int x,int l,int r){
my[x].l=l;my[x].r=r;my[x].lazy=0;
if(my[x].l==my[x].r){
my[x].num=ss[l-1]-'0';
// printf("my[%d].num=%d\n",x,my[x].num);
return;
}
int mid=(l+r)>>1;
build(x<<1,l,mid);
build((x<<1)|1,mid+1,r);
pushup(x);
}
void update(int x,int l,int r,int k){
if(my[x].l>=l&&my[x].r<=r){
my[x].num=(fs[my[x].r-my[x].l]*k)%mod;
my[x].ok=k;
my[x].lazy=1;
return;
}
pushdown(x);
int mid=(my[x].l+my[x].r)>>1;
if(l<=mid)update(x<<1,l,r,k);
if(r>mid)update(x<<1|1,l,r,k);
pushup(x);
}
ull query(int x,int l,int r){
if(my[x].l>=l&&my[x].r<=r)return my[x].num;
pushdown(x);
int mid=(my[x].l+my[x].r)>>1;
if(l>mid)return query(x<<1|1,l,r);
else if(r<=mid)return query(x<<1,l,r);
else{
ull t1=query(x<<1,l,r);
ull t2=query(x<<1|1,l,r);
int k=min(r,my[x].r)-mid;
return (t1*s[k]+t2)%mod;
}
pushup(x);
}
void pri(int n){
for(int i=1;i<=n*4;i++){
printf("my[%d].num=%llu\n",i,my[i].num);
}
}
int main()
{
/* std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);*/
init();
int n,q,t;
scanf("%d%d%d",&n,&q,&t);
q+=t;
scanf("%s",ss);
int len=strlen(ss);
build(1,1,len);
// pri(len);
for(int i=0;i<q;i++){
int op,l,r,d;
scanf("%d%d%d%d",&op,&l,&r,&d);
if(op==1)update(1,l,r,d);
else {
if(d==r-l+1){
printf("YES\n");
continue;
}
ull one=query(1,l,r-d);
// cout<<"one="<<one<<endl;
ull two=query(1,l+d,r);
// cout<<"two="<<two<<endl;
if(one==two)printf("YES\n");
else printf("NO\n");
}
}
return 0;
}
H.HDU - 1686 Oulipo
哈希水题,求模式串出现次数
1 |
|