河南萌新联赛2024第(二)场---E.好”字符

题目描述

字符串的循环同构:表示把字符串的左边第一位移到最后一位,新串再进行这样的操作,得到的一些字符串都是原串的循环同构,例如"bcda"、"cdab"、"dabc"都是"abcd"的循环同构。

给你两个长度相等的字符串 aaa 和 bbb ,字符串 aaa 和 bbb 均由小写字母组成。

当某个字符 xxx 在字符串 aaa 与字符串 bbb 或 bbb 的循环同构中出现的所有位置依次对应时(对于字符串的每一位,要么 aaa 和 bbb 的这一位都是该字符,要么都不为该字符),称该字符为“好”字符。例如:当 aaa = "acba",bbb = "bdaa"时,字符'a'与字符'b'为“好”字符

现在,我们想请你判断字符串 aaa 与字符串 bbb 中“好”字符的数量

输入描述:

第一行给你一个 nnn (1≤n≤106),n(1 \leq n \leq 10^6),n(1≤n≤106),n 为字符串 aaa 与 bbb 的长度。

第二行与第三行为字符串 aaa 和 bbb ,aaa 和 bbb 均由小写字母组成。

输出描述:

单行输出一个数字,表示“好”字符的个数。

示例1

输入

复制6 acabxb eababf

6
acabxb
eababf

输出

复制2

2

说明

当b的循环同构体为"ababfe"时,字符'a'为“好”字符,当b的循环同构体为"feabab"时,字符'b'为“好”字符。

示例2

输入

复制3 abc cde

3
abc
cde

输出

复制1

1

做法

本题的有两个关键。一是这个“循环同构”,在原字符串后面再复制一份原字符串,然后新的字符串中子串长度为n的子串就是原字符串的循环同构。二是分26个字母求哈希值,就是枚举字母,对于新串中是这个字母则值为‘1’,不是这个字母的话就是‘0’(别的也行)。然后遍历新字符串,找长度为n的区间,看他的哈希值和b串的哈希值是否相同,相同就ans++,然后找下一个可能的单词。

#include<bits/stdc++.h>
using namespace std;
const int P=131;
int n;
string a,b;
 long long hxc[10000010],hxd[10000010],p[10000010];//hxc得是1e6的两倍(复制了)
map<char,int> mpa,mpb,mp,mp3;
int ans;
int main(){
    scanf("%d",&n);
    cin>>a>>b;

    for(int i=0;i<n;i++){
        mpa[a[i]]++;
        mpb[b[i]]++;
    }

    for(int i=0;i<26;i++){//不是答案的字母
        if(mpa[i+'a']==0&&mpb[i+'a']==0) mp[i+'a']++;
        if(mpa[i+'a']!=mpb[i+'a']) mp[i+'a']++;
    }

    for(int i=0;i<26;i++){//是答案的字母
        if(mp[i+'a']==0) mp3[i+'a']++;
    }
    
    a=a+a;
    
    p[0]=1;
    for(int i=1;i<=2*n;i++) {
    	p[i]=p[i-1]*P;
	}
	
    for(map<char,int>::iterator it=mp3.begin();it!=mp3.end();it++){

        string c,d;

        for(int i=0;i<a.size();i++){//算a串的哈希值
            if(a[i]==it->first) c+='1'; 
            else c+='0';
            hxc[i+1]=hxc[i]*P+c[i];
        }
        
        for(int i=0;i<b.size();i++){//算b串的哈希值
            if(b[i]==it->first) d+='1';
            else d+='0';
            hxd[i+1]=hxd[i]*P+d[i];
        }
        
        for(int i=n;i<=a.size();i++){//区间哈希
             long long cntc;
            cntc=hxc[i]-hxc[i-n]*p[n];
            if(cntc==hxd[b.size()]){
                ans++;
                break;
            }
        }
        
    }
    
    cout<<ans;
}

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值