标签:Distance return String int tr CF1535F st dep id
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[j+a[i].st+1].fir+1ll*(str[j+a[i].st]-'a'+1))%mod1,
suf[j+a[i].st].sec=(31ll*suf[j+a[i].st+1].sec+1ll*(str[j+a[i].st]-'a'+1))%mod2,
suf[j+a[i].st].tri=(31ll*suf[j+a[i].st+1].tri+1ll*(str[j+a[i].st]-'a'+1))%mod3;
pre[a[i].st].fir=pre[a[i].st].sec=pre[a[i].st].tri=str[a[i].st]-'a'+1;
for(int j=1;j<n1;j++)
pre[j+a[i].st].fir=(31ll*pre[j+a[i].st-1].fir+1ll*(str[j+a[i].st]-'a'+1))%mod1,
pre[j+a[i].st].sec=(31ll*pre[j+a[i].st-1].sec+1ll*(str[j+a[i].st]-'a'+1))%mod2,
pre[j+a[i].st].tri=(31ll*pre[j+a[i].st-1].tri+1ll*(str[j+a[i].st]-'a'+1))%mod3;
if(!mp[a[i].hs])mp[a[i].hs]=++tot;vec[mp[a[i].hs]].push_back(i);
}
int pre=0;mp.clear();
for(int i=1;i<=tot;i++){
int siz=vec[i].size();ans+=1ll*siz*(siz-1);ans+=1337ll*siz*pre;pre+=siz;
for(int j=1;j<=siz;j++)id[j]=vec[i][j-1];
for(int j=n1-1;j>=0;j--){
for(int k=1;k<=siz;k++)tp[str[j+a[id[k]].st]-'a'+1].push_back(id[k]);int sum=0;
for(int k=26;k>0;k--){for(int l=0;l<(int)tp[k].size();l++)id[++sum]=tp[k][l];tp[k].clear();}
}
for(int j=2;j<=siz;j++){
int l=1,r=j-1,tmp=j-1;for(int k=0;k<n1;k++)modify(j-1,a[id[j-1]].st+k,a[id[j-1]].ed);
if(compare(id[j-1],id[j],n1)){while(l<r){int mid=l+r>>1;if(compare(id[j],id[mid],n1))r=mid;else l=mid+1;}tmp=l-1;}
ans-=2ll*(j-tmp-1);int head=0;if(!tmp)continue;
for(int k=1;k<n1;k++)
if(str[k+a[id[j]].st]<str[k+a[id[j]].st-1]){
l=1,r=tmp;if(!compare(id[tmp],id[j],head)){head=k;continue;}
while(l<r){int mid=l+r>>1;if(compare(id[j],id[mid],head))r=mid;else l=mid+1;}
ans-=1ll*found(tmp,a[id[j]].st+k,a[id[j]].ed)-1ll*found(l-1,a[id[j]].st+k,a[id[j]].ed);head=k;
}
if(compare(id[tmp],id[j],head)){l=1,r=tmp;while(l<r){int mid=l+r>>1;if(compare(id[j],id[mid],head))r=mid;else l=mid+1;}ans-=1ll*(tmp-l+1);}
}
for(int j=0;j<=siz;j++)root[j]=0;if(n1>9)T.clear();else T1.clear();
}
printf("%lld\n",ans);
return 0;
}
谢谢!!!
标签:Distance,return,String,int,tr,CF1535F,st,dep,id 来源: https://blog.csdn.net/Tan_tan_tann/article/details/117854600
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。