BZOJ2372 music

思路

两个字符串等价,相当于两个串中排名相同的字符,出现的位置相同。

于是我们哈希,分别维护每种字符的出现位置序列。
现在瓶颈在于得到每种字符的排名。
发现字符集只有 \(25\),可以直接枚举,桶排即可。然后再枚举判断对应排名的字符出现位置是否相同即可。

枚举一遍 \(B\)\(A\) 中可能出现的位置,复杂度 \(O(25n)\)

代码

const int N = 1e5+10,M = 2.5e4+10;
const ull base = 2333;
int n,m,c,a[N],b[M],cnt[26];
ull mul[N],hb[26],ha[26],h1[26][N],h2[26][M],B,A;
inline ull hs(ull h[],int l,int r){
	return h[r]-h[l-1]*mul[r-l+1];
}
inline int check(){
	for(int i=1;i<=25;++i) if(ha[i]!=hb[i]) return 0;
	return 1;
}
vector <int> ans;
int main(){
	// freopen("in.in","r",stdin); 
	// freopen("out.out","w",stdout);
	
	read(n,m,c);
	if(n<m){
		puts("0");
		return 0;
	}
	mul[0] = 1;
	for(int i=1;i<=n;++i) mul[i] = mul[i-1]*base;
	for(int i=1;i<=n;++i){
		read(a[i]);
		for(int j=1;j<=25;++j) h1[j][i] = h1[j][i-1]*base+(a[i]==j)*base;
	}
	for(int i=1;i<=m;++i){
		read(b[i]);
		++cnt[b[i]];
		for(int j=1;j<=25;++j) h2[j][i] = h2[j][i-1]*base+(b[i]==j)*base;
	}
	for(int i=1,d = 0;i<=25;++i) if(cnt[i]) hb[++d] = h2[i][m];
	for(int i=1;i<=25;++i) cnt[i] = 0;
	for(int i=1;i<=m-1;++i) ++cnt[a[i]];
	for(int l=1,r=m;r<=n;++l,++r){
		--cnt[a[l-1]];
		++cnt[a[r]];
		for(int j=1;j<=25;++j) ha[j] = 0;
		for(int j=1,d = 0;j<=25;++j) if(cnt[j]) ha[++d] = hs(h1[j],l,r);
		if(check()) ans.push_back(l);
	}
	printf("%d\n",(int)ans.size());
	for(int i=0;i<(int)ans.size();++i) printf("%d\n",ans[i]);

	// fclose(stdin);
	// fclose(stdout);
	return 0;
}
posted @ 2025-11-15 19:38  Tmbcan  阅读(12)  评论(0)    收藏  举报