AtCoder Grand Contest 039

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;
}

咕咕。

猜你喜欢

转载自www.cnblogs.com/lyfoi/p/11626196.html
今日推荐