Iahubina is tired of so many complicated languages, so she decided to invent a new, simple language. She already made a dictionary consisting of n 3-words. A 3-word is a sequence of exactly 3 lowercase letters of the first 24 letters of the English alphabet (a to x). She decided that some of the letters are vowels, and all the others are consonants. The whole language is based on a simple rule: any word that contains at least one vowel is correct.
Iahubina forgot which letters are the vowels, and wants to find some possible correct sets of vowels. She asks Iahub questions. In each question, she will give Iahub a set of letters considered vowels (in this question). For each question she wants to know how many words of the dictionary are correct, considering the given set of vowels.
Iahubina wants to know the xor of the squared answers to all the possible questions. There are 224 different questions, they are all subsets of the set of the first 24 letters of the English alphabet. Help Iahub find that number.
Input
The first line contains one integer, n (1 ≤ n ≤ 104). Each of the next n lines contains a 3-word consisting of 3 lowercase letters. There will be no two identical 3-words.
Output
Print one number, the xor of the squared answers to the queries.
Examples
inputCopy
5
abc
aaa
ada
bcd
def
outputCopy
0
题意:
有n个长度为3的单词,由前24种字母组成。
选择一些字母为原因,有
2
24
2^{24}
224种选择方式。一个单词为正确单词为右至少一个元音。那么对于所有的选择方式,结果为正确单词数量的平方,求所有选择方式对应结果的异或值。
思路:
寻找正确单词很麻烦,我们寻找对于某个选择方式状态的不正确单词。
定义
d
p
[
i
]
dp[i]
dp[i]为,选择状态为
i
i
i,其中二进制位1代表这个字母不是元音,对应的单词数目。
则有 d p [ i ] = d p [ i ] + ∑ d p [ j ] , j ∈ i dp[i] = dp[i] + ∑dp[j],j∈i dp[i]=dp[i]+∑dp[j],j∈i,枚举子集可以用高维前缀和的方法。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 7;
int a[maxn];
int dp[(1 << 24) + 7];
int main() {
int n;scanf("%d",&n);
for(int i = 1;i <= n;i++) {
char s[10];scanf("%s",s);
int sta = 0;
for(int j = 0;j < 3;j++) sta |= (1 << (s[j] - 'a'));
dp[sta]++;
}
int num = (1 << 24) - 1;
int ans = 0;
for(int j = 0;j <= 23;j++) { //这个循环要在外面,否则子状态可能没算完
for(int i = num;i >= 0;i--) { //代表哪些状态不是元音,逆序,保证不会重复加
if(i & (1 << j)) {
dp[i] += dp[i ^ (1 << j)];
}
}
}
for(int i = 0;i < num;i++) {
ans ^= (n - dp[i]) * (n - dp[i]);
}
printf("%d\n",ans);
return 0;
}