【异或哈希】CF855 div3 F

感觉这道题跟之前有一题特别像,都是异或哈希

感觉这种题应该很典,记录一下

(66条消息) Codeforces Round #841 (Div. 2) and Divide by Zero【异或差分+动态map维护】 2022 C. Even Subarrays_lamentropetion的博客-CSDN博客

Problem - F - Codeforces

题意:

给你n个字符串,求对 (i, j) 的数量,使得

c[i] = s[i] + s[j] (两个字符串串联起来)

1.c[i]的长度为奇数

2. c[i] 所包含的字符种类恰好是 25 个

3. c[i] 所包含的每种字符的出现次数都为奇数

思路:

首先,目标状态是不确定的,不知道目标状态少哪个字符,因此我们去枚举少了哪个字符

当2和3都满足时,1一定满足

确定完目标状态之后,注意到我们要去n^2枚举两个指针,那么按照套路的做法,我们去枚举其中一个指针,然后去考虑限定条件来得到另一个指针

它的限定条件和全局的哈希有关,因此我们去维护全局的哈希

那么,全局的哈希去维护什么值呢?很明显是去维护每个字符是否出现以及每个字符的出现次数的奇偶性

a[i]表示每个字符串中每个字符是否出现,b[i]表示每个字符串中字符的出现次数的奇偶性

所以在枚举之前,可以先去预处理这两个哈希

考虑去枚举i,确定了两个字符串连起来的状态,我们怎么去确定j

即s[j]的限定条件是什么

  1. 每种字符出现次数为奇数

  1. s[i]和s[j]的字符种类加起来必须有25种

假设 s[i] 对应的 b[i] 是 k,和法的 c[i] 对应的 b[i] 是 q, s[j] 对应的 b[j] 是 p,那 s[i] + s[j] 对应的 b[i] 其实就是 k^p

因此直接去维护动态map就能计数出所有满足条件的对数

当然不能忘记清空cnt数组

Code:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <map>
#include <queue>
#include <set>
//#define int long long
using namespace std;
using i64 = long long;
const int mxn=1e6+10;
const int mxe=1e6+10;
const int mod=1e9+7;

string s;
int n;
int a[mxn],b[mxn],cnt[1<<26];
void solve(){
    s.clear();
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    memset(cnt,0,sizeof(cnt));
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>s;
        for(int j=0;j<s.size();j++){
            a[i]|=(1<<(s[j]-'a'));
            b[i]^=(1<<(s[j]-'a'));
        }
    }
    i64 ans=0;
    for(int i=0;i<26;i++){
        int S=(1<<26)-1-(1<<i);
        for(int j=1;j<=n;j++){
            if(!((a[j]>>i)&1)){
                cnt[b[j]]++;
                ans+=cnt[S^b[j]];
            }
        }
        for(int j=1;j<=n;j++){
            if(!((a[j]>>i)&1)){
                cnt[b[j]]--;
            }
        }
    }
    cout<<ans<<'\n';
}
signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int __=1;//cin>>__;
    while(__--)solve();return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值