Codeforces Round 855 (Div. 3)
D
题意:
有一个字符串s, 每次可以删除连续的两个字符,问可以得到多少种不同的字符串
思路:
如果每个字符都不一样,那么答案就是n - 1, 如果s[i - 1] = s[i + 1]说明会重复计算一次所以答案减一
inline void solve()
{
int n; cin >> n;
string s; cin >> s;
int ans = n - 1;
for (int i = 1; i < n - 1; i++)
if (s[i - 1] == s[i + 1]) ans--;
cout << ans << endl;
}
E
题意:
给你一个字符串s, 如果 |i - j| = k 或者 |i - j| = k + 1 那么你可以交换(s[i], s[j]), 问能不能通过若干次操作将s变成t
思路:
对于 u 来说, u - k <=> u <=> u + k, 这三个点可以任意交换,对于k + 1也是一样的道理,也就是说在一个连通块里的点可以任意交换,
所以对于同一个连通块而言,s和t在这个连通块里面的字符个数和类型必须完全一样才可以通过交换使得位置也一样
inline void solve()
{
int n, k; cin >> n >> k;
string a, b; cin >> a >> b;
DSU dsu(n);
for (int i = 0; i < n; i++)
{
if (i + k < n) dsu.merge(i, i + k);
if (i + k + 1 < n) dsu.merge(i, i + k + 1);
}
std::vector<array<int, 26>> cnt(n);
for (int i = 0; i < n; i++) cnt[dsu.find(i)][a[i] - 'a']++;
for (int i = 0; i < n; i++) cnt[dsu.find(i)][b[i] - 'a']--;
for (int i = 0; i < n; i++)
for (int j = 0; j < 26; j++)
{
if (cnt[i][j] != 0)
{
cout << "No" << endl;
return;
}
}
cout << "Yes" << endl;
}
F
题意:
给你 n 个字符串, 问有多少点对(i, j)满足以下条件?
- s[i] + s[j] 的长度为奇数
- s[i] + s[j] 中每个字符出现的次数为奇数
- s[i] + s[j] 中一共有 25 种字符
思路:
显然只要满足要求 2, 3那么 1 自然就满足了,所以可以二进制压缩,
定义a[i]: s[i]的字符种类情况,1 代表出现, 0 代表没出现
定义b[i]: s[i]的字符次数情况, 1 代表出现了奇数次, 0 代表偶数次
因为要求字符种类为25,那么只会缺少一种字符,直接枚举就行了
inline void solve()
{
int n; cin >> n;
std::vector<int> a(n, 0), b(n, 0);
for (int i = 0; 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'));
}
}
vector<int> cnt(1 << 26);
LL ans = 0;
for (int i = 0; i < 26; i++)
{
int t = (1 << 26) - 1 - (1 << i); // 假设缺少第 i 位
for (int j = 0; j < n; j++)
{
if (!((a[j] >> i) & 1)) // s[j]不包含第 i 位, s[i] + s[j] 的b[]
{
cnt[b[j]]++;
ans += cnt[t ^ b[j]]; // 异或等价加减(只关注奇偶的情况下)
}
}
for (int j = 0; j < n; j++)
if (!((a[j] >> i) & 1)) cnt[b[j]] = 0; // 清空数组防止影响下一组
}
cout << ans << endl;
}

浙公网安备 33010602011771号