题目大意:
n(≤1e4)n(\le1e4)n(≤1e4)个长度为333的字符串(字符为:′a′−′x′'a'-'x'′a′−′x′(24个字符)),当一个字符串包含至少一个关键字符,则这个字符串是正确的,而关键字符的方案数为2242^{24}224,对每个方案的正确字符串个数平方求异或和
解题思路:
- 首先非常显而易见的是,可以将字符串先压缩成长度为24的2进制串,而对于每个方案也可以这样表示
- 对于每个方案表示的状态ststst,实际上是求∑st&i!=0ai\sum_{st \& i != 0}a_i∑st&i!=0ai,aia_iai为状态为iii的字符串有多少个,即与ststst有交集的字符串个数多少
- 通过状压dpdpdp(这道题里称作SOSdpSOSdpSOSdp),可以求出dp[i]=∑st&i=iaidp[i]=\sum_{st \& i = i}a_idp[i]=∑st&i=iai,即状态iii子集的贡献个数
- 知道dp[i]dp[i]dp[i],那么dp[∼i]dp[\sim i]dp[∼i]就为不与i有交集的字符串个数,所以n−dp[∼i]n-dp[\sim i]n−dp[∼i]就为与iii有交集的字符串个数
- 最后统计答案就好
- 注意dpdpdp顺序,正序会统计重复,逆序就不会
AC代码:
#include <bits/stdc++.h>
#define ft first
#define sd second
#define pb push_back
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) //不能跟puts混用
#define seteps(N) fixed << setprecision(N)
#define endl "\n"
const int maxn = 1e5 + 10;
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
const ll mod = 1e9 + 7;
int n, dp[(1 << 24) + 100];
string s;
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> s;
int res = 0;
for (int j = 0; j < 3; j++) res |= (1 << (s[j] - 'a'));
dp[res]++;
cout << res << endl;
}
for (int j = 0; j < 24; j++)
for (int i = (1 << 24); i > 0; i--) { //倒着来就不会有重复
if ((i >> j) & 1)
dp[i] += dp[i ^ (1 << j)];
}
int ans = 0;
for (int i = 0; i <= 56; i++) cout << dp[i] << endl;
for (int i = 0; i < (1 << 24); i++) ans ^= (n - dp[i]) * (n - dp[i]);
cout << ans << endl;
return 0;
}