牛客周赛 Round 32 E.小红的回文数【挖掘性质+哈希前缀和】

原题链接:https://ac.nowcoder.com/acm/contest/75174/E

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

小红定义一个整数是“好数”,当且仅当该整数通过重排之后可以形成回文数。(可以包含前导零)
现在小红拿到了一个正整数x,小红想截取一段连续区间得到好数,她想知道有多少种不同的方案?

输入描述:

输入一个正整数x。
1≤x≤10^(10^5)

输出描述:

得到“好数”的方案数。

示例1

输入

110

输出

5

说明

长度为 1 的区间,三个都是合法的。
长度为 2 的区间,"11"是合法的,"10"是不合法的。
长度为 3 的区间, "110"是合法的。

解题思路:

当截取的区间长度为偶数时,每种字符都只能出现偶数次,

当截取的区间长度为奇数时,有且仅有一种字符出现奇数次。

综上所述最多只能有一种字符出现奇数次。

(1)所有字符出现偶数次

(2)0,1,2,3,4,5,6,7,8,9中的某一种字符出现奇数次。

由于要求的是满足要求的子区间个数,我们可以使用前缀和进行维护,到这里我们还需要知道一个性质。

性质如下:

  • 奇数-奇数=偶数
  • 偶数-偶数=偶数
  • 奇数-偶数=奇数
  • 偶数-奇数=奇数

我们不妨用一个二进制数temp表示当前某种数出现次数的奇偶性,例如temp二进制数的第i位1表示数字i出现奇数次,否则表示数字i出现偶数次,比如说temp的第0位为1表示0出现的次数为奇数,否则表示0出现的次数为偶数。

当前位置前缀和temp,如果要使得子区间所有数字都出现偶数次,那么前面位置前缀和表示应该和temp一样,俩个前缀和相减才能保证每种数字出现偶数次。

当前位置前缀和temp,如果要使得某一种数字出现奇数次,其他数字都出现偶数次,例如数字i出现奇数次,那么前面位置前缀和应该为temp^(1<

时间复杂度:O(n*10),枚举字符串s时间为O(n),枚举某一种出现次数为奇数的字符,总共有10种,所以时间为O(10),所以最终时间为O(10*n),时间复杂度为O(n),常数为10。

空间复杂度:O(n),使用一个哈希表,存储所有前缀和的哈希值。

cpp代码如下:

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
typedef long long LL;
typedef pair PII;

const int N = 1e5 + 10;
int n, m;
unordered_mapmp;
int main()
{
    string s;
    cin>>s;
    n=s.size();
    int temp=0;
    mp[temp]++;  //所有数字出现0次,加入哈希表
    LL sum=0;  //sum记录答案
    for(int i=0;i

你可能感兴趣的:(基础算法,哈希算法,算法,数据结构)