[CF1535F]String Distance
Posted Tan_tan_tann
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF1535F]String Distance相关的知识,希望对你有一定的参考价值。
String Distance
题解
《关于因为卡模数所以被笔者称之为"贞卡模"的那件事》
都在test61WA了,是jzm的错吗
test 5与test 6混入其中
首先我们可以考虑 f ( s i , s j ) f(s_{i},s_{j}) f(si,sj)的值。
- 当两者某个字符的数量不同时,两者永远变不一起去,代价为
1337
1337
1337
奇怪的数字。 - 当两者有差异的子串间有一个是有序的,我们只需要排一个,代价为 1 1 1。
- 当两者有差异的子串都是无序的时,我们需要将两者都排一遍序,代价为 2 2 2。
- 当两者没有差异时,代价为 0 0 0
第一种与第四种可以直接用hash求出,关键是第二种与第三种该怎么求。
我们可以考虑将所有的字符串串按每种字符的数量分类,再通过基排排一遍序。
此时就跟后缀数组一样,我们得到的相邻的两个字符串的
l
c
p
lcp
lcp一定是最大的。
我们考虑对于每个字符串划分出它的极大有序区间,与贡献为
1
1
1的两个串的差异子串一定是两者中其中一个极大有序区间的子区间。
当字符串是按从大到小的方法排列时,拥有差异子串部分是有序那一个串一定是在最后的。
对于其它串,当且仅当除该有序区间的部分都相同时才会贡献为
1
1
1。
对于前半部分,由于前缀相同的子串是连续的,我们可以通过二分找到与其极大有序区间的前缀相同的子串的区间。
字符串比较的部分我们可以通过字符串Hash来做到
O
(
1
)
O\\left(1\\right)
O(1)。
而后缀部分,我们可以通过可持久化
T
r
i
e
Trie
Trie树来维护。
我们将每个后缀的Hash值都加入
T
r
i
e
Trie
Trie树中,用差分的方法买得到前缀相同的区间中,后缀也与它相同的串的数量。
这些串与该串的贡献为
1
1
1,而该类其余的串与其贡献为
2
2
2,其它类的串与其贡献为
1337
1337
1337。
对于完全相同的串,排序后一定是连续的,我们可以先二分找到,计算前三类贡献时就先将其排除掉,免得之后还要计算极大有序区间数量太麻烦。
由于我们要
H
a
s
h
Hash
Hash的部分实在太多,避免重复,我们得采用三哈希。还得疯狂调模数
但我们可以发现,由于
n
⋅
∣
s
1
∣
⩽
2
×
1
0
5
n\\cdot|s1|\\leqslant 2\\times 10^5
n⋅∣s1∣⩽2×105,字符串较长的串,串的数量其实很少,串数量多的其实是串长很少的串。
但如果对于较短的串还要三哈希跑
90
90
90层实在太麻烦了,所以对于这部分串,我们可以直接建
T
r
i
e
Trie
Trie树出来。
这样常数会稍微小一点。
时间复杂度
O
(
n
∣
s
∣
l
o
g
n
)
O\\left(n|s|log\\,n\\right)
O(n∣s∣logn),但模数贞德很难调。
源码
卡了半天,最后发现竟然是因为
j
z
m
jzm
jzm不能赋
233333
233333
233333,果然是因为
j
z
m
jzm
jzm太强了。
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
#define lowbit(x) (x&-x)
#define reg register
#define mkpr make_pair
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x3f3f3f3f;
const int mod1=998244353;
const int mod2=1e9+7;
const int mod3=1e9+9;
const int iv2=5e8+4;
const int lim=1000000;
const int jzm=1e6+7;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
typedef pair<int,int> pii;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int gcd(int x,int y){return !y?x:gcd(y,x%y);}
int n,sum,num[30],tot,id[MAXN],n1,root[MAXN];LL ans;
char str[MAXN],ss[10];
struct hashnode{
int fir,sec,tri;
int ask(int dep){
if(dep>=60)return (fir>>dep-60)&1;
if(dep>=30)return (sec>>dep-30)&1;
return (tri>>dep)&1;
}
bool operator == (const hashnode &rhs)const{
return fir==rhs.fir&&sec==rhs.sec&&tri==rhs.tri;
}
}suf[MAXN],pre[MAXN];
struct ming{int st,ed,len,hs;}a[MAXN];
struct node{int ch[2],sum;};
struct node1{int ch[30],sum;};
vector<int>vec[MAXN],tp[30];
map<int,int>mp;
class TrieTree{
public:
int tot;node tr[MAXN*90];
void clear(){tot=0;tr[0].sum=tr[0].ch[0]=tr[0].ch[1]=0;}
void insert(int &now,int las,hashnode val,int dep=89){
if(now==las||!now)tr[now=++tot]=tr[las];
if(dep<0){tr[now].sum++;return ;}
if(val.ask(dep))insert(tr[now].ch[1],tr[las].ch[1],val,dep-1);
else insert(tr[now].ch[0],tr[las].ch[0],val,dep-1);
}
int query(int rt,hashnode val,int dep=89){
if(!rt)return 0;if(dep<0)return tr[rt].sum;
if(val.ask(dep))return query(tr[rt].ch[1],val,dep-1);
return query(tr[rt].ch[0],val,dep-1);
}
}T;
class superTrie{
public:
int tot;node1 tr[MAXN*10];
void clear(){tot=0;tr[0].sum=tr[0].ch[0]=tr[0].ch[1]=0;}
void insert(int &now,int las,int dep){
if(now==las||!now)tr[now=++tot]=tr[las];
if(dep<0){tr[now].sum++;return ;}
insert(tr[now].ch[ss[dep]-'a'],tr[las].ch[ss[dep]-'a'],dep-1);
}
int query(int rt,int dep){
if(!rt)return 0;if(dep<0)return tr[rt].sum;
return query(tr[rt].ch[ss[dep]-'a'],dep-1);
}
}T1;
bool compare(int x,int y,int len){if(!len)return 1;return pre[len+a[x].st-1]==pre[len+a[y].st-1];}
void modify(int i,int l,int r){
if(n1>9)T.insert(root[i],root[i-1],suf[l]);
else{
for(int j=0;j<n1;j++)ss[j]=0;
int sm=0;for(int j=l;j<r;j++)ss[sm++]=str[j];
T1.insert(root[i],root[i-1],sm-1);
}
}
int found(int i,int l,int r){
if(n1>9)return T.query(root[i],suf[l]);
else{
for(int j=0;j<n1;j++)ss[j]=0;
int sm=0;for(int j=l;j<r;j++)ss[sm++]=str[j];
return T1.query(root[i],sm-1);
}
}
signed main(){
read(n);
for(int i=1;i<=n;i++){
scanf("\\n%s",str+sum);a[i].st=sum;
a[i].len=(int)strlen(str+sum);sum+=a[i].len;n1=a[i].len;a[i].ed=sum;
for(int j=1;j<=26;j++)num[j]=0;
for(int j=0;j<a[i].len;j++)num[str[j+a[i].st]-'a'+1]++;
for(int j=1;j<=26;j++)a[i].hs=(1ll*jzm*a[i].hs+1ll*num[j])%mod1;
if(n1>9)for(int j=n1-1;j>=0;j--)
suf[j+a[i].st].fir=(31ll*suf[jCF161D Distance in Tree
[CF1032D] Barcelonian Distance - 计算几何
[CF1032D] Barcelonian Distance - 计算几何
[CF442E]Gena and Second Distance
CF&&CC百套计划2 CodeChef December Challenge 2017 Chef and Hamming Distance of arrays