Codeforces Round 855 (Div. 3) F

F

核心思路

首先我们可以知道的是只要满足了条件2和条件3必然会满足条件1.因为奇数和奇数的乘积一定是奇数。这一个比较显而易见的性质。

然后就是我们需要思考我们得使用什么方式来表示我们的条件2和条件3的状态呢。这里就运用到了状态压缩的知识,也就是我们使用二进制序列来表示我们的状态,因为总共的状态也只有\(1<<26\).也就是只需要表示26个字母就好了。

集合定义

\(a[i]表示第i个字符串中每个字母的是否出现过\)

\(b[i]表示第i个字符串中每个字母出现的次数是否是奇数\)

接下来就是怎么预处理a数组和b数组呢,其实不难发现a数组的处理可以采用位或操作,而b数组可以采用异或操作。这个自己模拟下就好了。

因为题目只需要25个字母,所以我们可以枚举缺失的哪个字母。再就是从前往后枚举我们的字符串,假设当前枚举的是字符串i,先看他的是不是只缺少一个字符,也就是a[i]的状态,再就是先搞出来我们目标的b[i],再看那些字符串是不是有对应的b[i].

这些每个合法一半的状态可以采用cnt数组来存储。

// Problem: F. Dasha and Nightmares
// Contest: Codeforces - Codeforces Round 855 (Div. 3)
// URL: https://codeforces.com/contest/1800/problem/F
// Memory Limit: 512 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define NO {puts("NO") ; return ;}
#define YES {puts("YES") ; return ;}
#define endl "\n"
const int N=1e6+10;
int n;
int a[N];
int b[N];
int cnt[1<<26];

signed main()
{
	IOS;
cin>>n;
for(int i=1;i<=n;i++)
{
	 string s;
	 cin>>s;
	 for(int j=0;j<s.size();j++)
	 {
	 a[i] |= (1 << (s[j] - 'a')), b[i] ^= (1 << (s[j] - 'a'));
	 }
}
LL 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<<endl;
return 0;

}
posted @ 2023-03-07 15:19  努力的德华  阅读(36)  评论(0)    收藏  举报