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;
}
标签:855,cnt,int,Codeforces,数组,字符串,Div,define
From: https://www.cnblogs.com/xyh-hnust666/p/17188229.html