codeforecs 316G2 哈希+优化
https://codeforces.com/contest/316/problem/G2
给定一个母串$s$,问母串$s$有多少本质不同的子串$t$是“好”的。
一个字符串$t$是好的,仅当$t$满足了所有的$n$个条件。
第$i$个条件用一个三元组$(p_i,L_i,R_i)$来描述。
其中$p_i$为一个字符串,$L_i,R_i$为整数,且$L_i\leq R_i$。
仅当字符串$t$在$p_i$中出现次数在$L_i$到$R_i$之间时,它是"好"的。
$|s|,|p_i|\leq 2\times 10^3,n\leq 10$
专门说一下G2吧,G2感觉是裸哈希+暴力,一眼复杂度$O(n*(|s|^2+\sum|p|^2)*hashmap)$
但是ac过程十分艰苦,首先,如果是单哈希$mod1e9+7$,基本上肯定会碰撞导致wa
(1e9的哈希空间,基本上1e6次访问就能发生上百次碰撞)
然后换成ull单哈希,感谢cf爸爸不卡ull.
但是还是T,
然后换成u_map和u_set,但是还是T
然后加入优化
1.如果枚举的p的子串长度>s的长度,break
2.枚举p子串起点,再枚举p子串终点,如果当前p的子串不存在于s中,break,后面的必不存在(和上面的其实重复了)
3.从枚举s的子串改为枚举p的子串(这个实际上应该没快多少)
4.开两个set保存s满足前i个限制的子串,每次滚动指针,s1,s2,
其中s1保存了当前满足前i个限制的所有子串
如果当前限制l==0,那么枚举p的所有子串,所有出现次数>r的,从s1中删除,然后暂时不交换指针
如果当前限制l>0,那么枚举p的所有子串,只把出现次数满足约数的放入s2,然后交换s1,s2指针
以上的优化其实都挺片面,感谢cf爸爸不卡之恩
#include<bits/stdc++.h>
#define ull unsigned long long
#define fi first
#define se second
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define rep(ii,a,b) for(int ii=a;ii<=b;++ii)
using namespace std;//head
const int maxn=2e3+10,maxm=1e3+10;
int n,m;
const ull decm=131;
ull pw[maxn];
void init(int n=maxn-5){pw[0]=1;rep(i,1,n) pw[i]=pw[i-1]*decm;}
class strhash{public:
ull hs[maxn],len;
void calhs(char *s,int n){len=n;rep(i,0,len-1)hs[i+1]=hs[i]*decm+s[i];}
inline ull geths(int a,int b){return hs[b]-hs[a-1]*pw[b-a+1];}
}mps;
unordered_map<ull,int> cnt;
unordered_set<ull> vis,s1,s2;
char s[maxn];
int l,r;
int main() {IO;
init(maxn-5);cin>>s>>n;
m=strlen(s);mps.calhs(s,m);
rep(i,1,m)rep(j,i,m) {
ull x=mps.geths(i,j);
if(!vis.count(x)){
vis.insert(x);
s1.insert(x);
}
}
if(n==0){
cout<<vis.size();
return 0;
}
int ans=0;
unordered_set<ull> &sub=s1,&tmp=s2;
rep(i,1,n){
cin>>s>>l>>r;
int len=strlen(s);cnt.clear();
mps.calhs(s,len);
rep(j,1,len)rep(k,j,len) {
if(k-j+1>m) break;
ull x=mps.geths(j,k);
if(!vis.count(x)) break;
cnt[x]++;
}
if(l==0){
for(auto x:cnt)if(sub.count(x.fi)&&x.se>r)sub.erase(x.fi);
if(i==n)ans=sub.size();
continue;
}
for(auto x:cnt)if(sub.count(x.fi)&&x.se>=l&&x.se<=r)tmp.insert(x.fi);
sub.clear();
if(i==n)ans=tmp.size();
swap(tmp,sub);
}
cout<<ans<<endl;
}

浙公网安备 33010602011771号