【2017年360机试题】偶串

1题意

定义个字符串S是偶串当且仅当S中的每一种字符都出现了偶数次。例如S=‘‘abbacc′′就是一个偶串,因为abc三种字符都出现了偶数次。

题目为输入一个字符串,问S有多少个子串是偶串。

对于任意的,我们使用符号[L,R]表示子串。例如输入的字符串S=‘‘aabbaa′′,它有[1,2],[3,4],[5,6],[1,4],[2,5],[3,6],[1,6]这7个子串是偶串。

2解法

本题有一个显而易见的O(n^3)的解法。枚举子串的左右端点L, R,再检查子串[L, R]是否为一个偶串,如果是,答案加1。最后输出总的偶串个数。这种做法虽然能给出正确答案,但是复杂度太高,大数据会超时。
上述算法可以优化成一个O(n^2)的算法。当我们枚举了左右端点L, R之后,有没有方法可以O(1)的检查子串[L, R]是否为一个偶串?注意到英文字母一共只有26个,我们要求出这26个字符在[L, R]中分别出现了多少次。为了方便表示,我们把字母a对应到数字0,字母b对应到数字1,依次类推字母z对应到数字25。对于 ,定义f(i, j)为在 中,数字j对应的字母出现了多少次。例如S=‘‘aabbaa′′时,f(3,0) = 2,表示‘‘aab′′中a出现了3次。
用如下方法计算f(i, j):


这样,[L, R]中字母a出现的次数就是f(R,0)-f(L-1,0),依次检查26个字母的出现次数可判断[L,R]是否为偶串。
注意到其实我们不关心具体个数,只关心每个字母出现次数的奇偶性,于是上述递推式中的加1可以改成异或1,从而 ,表示在 中,数字j对应的字母出现次数的奇偶性。对于一个特定的 ,就可以压缩成一个26位的二进制数g(i),特别地,g(0) = 0。判断[L, R]是否为偶串只需要检查g(R)异或g(L-1)是否为0。
可是上述算法的复杂度依然很高。对于任意的 ,考虑所有以i为结束位置的子串中,有多少子串是偶串。注意到x异或x等于0。所以实际上就是在求 中值等于g(i)的个数。使用C++中的map可以快速的实现这一功能,复杂度

3代码

#include <bits/stdc++.h>
#define maxn 100009
using namespace std;
char s[maxn];
map<int,int>mp;
int n;
int main(){
    scanf("%s",s);
    n = strlen(s);
    mp[0] = 1;
    int cur = 0;
    long long ans = 0;
    for(int i = 0; i < n; i++){
        int x = s[i] - 'a';
        cur ^= (1 << x);
        ans += mp[cur];
        mp[cur]++;
    }
    cout << ans << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值