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

文章讨论了如何通过计算整数x的子区间,使得这些子区间重排后形成回文数,利用前缀和和二进制表示奇偶性来确定方案数,给出了一段C++代码实现。
摘要由CSDN通过智能技术生成

原题链接: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<<i),其他位置奇偶性相同,相减就是偶数次,第i个位置奇偶性不同,那么相减为奇数,俩个前缀和相减才能保证只有某一种数字出现奇数次,其他数字都出现偶数次。

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

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

cpp代码如下:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <unordered_map>

using namespace std;
typedef long long LL;
typedef pair<int, int> PII;

const int N = 1e5 + 10;
int n, m;
unordered_map<int,int>mp;
int main()
{
    string s;
    cin>>s;
    n=s.size();
    int temp=0;
    mp[temp]++;  //所有数字出现0次,加入哈希表
    LL sum=0;  //sum记录答案
    for(int i=0;i<n;i++)
    {
        temp^=(1<<(s[i]-'0')); //异或上当前位置,表示当前位置结尾的前缀和
        sum+=mp[temp];  //所有数字俩个前缀和奇偶性相同,也就是所有字符出现偶数次的区间
        for(int j=0;j<10;j++)
        {
            sum+=mp[temp^(1<<j)]; //某个数字出现奇数次,其他数字出现偶数次的区间。
        }
        mp[temp]++;  //当前位置结尾的前缀和加入哈希表
    }
    cout<<sum;
    return 0;
}
  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值