A Connection and Disconnection
Description
将一个由小写字母构成字符串 \(S\) 复制 \(k\) 遍得到 \(T\),可以将 \(T\) 中的字母更换为任意一个字母,求至少在 \(T\) 中 更换几个字符才能没有两个相邻的相同的字母。
Solution
对于字符串 \(T\),它的相邻相同字母分成两个情况,一个是 \(S\) 内部,一个是复制 \(S\),在两个 \(S\) 的相交。若没有相交的贡献非常简单,两个相邻相同的字符将右边的字符换掉即可。如果有相交贡献,即为 \(S\) 的最后一个字符与他开头的字符相同,那么分两种情况。一种是 \(S\) 的末尾已经被更换了,一定能让 \(S\) 的末尾更换的字母与 \(S\) 开头的不同,另一种是 \(S\) 的末尾没有被更换,那么要在与它相交的 \(S\) 的开头更换。如果一个 \(S\) 的开头被更换了,那么它的贡献是 \(1\),否则为 \(0\)。
现在可以写暴力了,但是可以发现内部的贡献是一样的,而相交的贡献为 \(0\) 或 \(1\),可以发现,所有 \(S\) 的相交贡献的可能有 \(3\) 种情况,一种是贡献都为 \(1\),另一种是贡献都为 \(0\),还有一种是 \(0\) 与 \(1\) 交替。我们可以尝试前两个数把规律找出来,然后用公式求。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int read() {
int x = 0, f = 0; char ch = 0;
while (!isdigit(ch)) f |= ch == '-', ch = getchar();
while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
return f ? -x : x;
}
bool f;
int get(string s)
{
int ans = 0;
if (f) ans++, s[0] = '#';
for (int i = 1; i < s.size(); i++)
if (s[i] == s[i - 1]) ans++, s[i] = '#';
if (s[s.size() - 1] == s[0] && s[s.size() - 1] != '#') f = 1;
if (s[s.size() - 1] == '#') f = 0;
return ans;
}
int main(){
string s; cin >> s; int k = read();
ll ans = get(s);
if (f) {
int nxt = get(s);
if (f) ans += 1ll * nxt * (k - 1);
else ans += 1ll * nxt * (k - 1 - k / 2) + 1ll * ans * k / 2;
}
else ans += 1ll * (k - 1) * get(s);
printf("%lld\n", ans);
return 0;
}
B Graph Partition
Description
将一张无向图染色,相邻节点颜色相邻,求最多能染多少颜色。如果没有方案输出 \(-1\)。
Solution
先考虑无解的情况,如果有一个奇环,那么颜色相邻就自相矛盾了,所以先特判掉。然后贪心的考虑,只要让最长的一条路径每条边的颜色不同就可以了,其他的边可以不顾一切的为最长路径上的边服务,所以答案是所有两点最短路的最大值 \(+1\)。
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 500 + 5, INF = 0x3f3f3f3f;
int read() {
int x = 0, f = 0; char ch = 0;
while (!isdigit(ch)) f |= ch == '-', ch = getchar();
while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
return f ? -x : x;
}
int a[N][N];
int main() {
int n = read();
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++){
char c; scanf(" %c", &c); a[i][j] = c - '0';
if (!a[i][j] && i != j) a[i][j] = INF;
}
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
a[i][j] = min(a[i][j], a[i][k] + a[k][j]);
int ans = -INF;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if ((a[i][j] & 1 == 0 && (a[1][i] & 1) != (a[1][j] & 1) || (a[i][j] & 1 && (a[1][i] & 1) == (a[1][j] & 1)))) {
puts("-1");
return 0;
}
ans = max(ans, a[i][j]);
}
}
printf("%d\n", ans + 1);
return 0;
}
咕咕。