Codeforces 1492E Almost Fault-Tolerant Database

Description

给定 $n$ 个长度为 $m$ 的串 $s_1, s_2, \cdots, s_n$,找到一个长度为 $m$ 的串 $ans$,使得 $ans$ 与任意 $s_i$ 至多有两个位置不同。如果无解,输出 No

$nm \le 2.5 \times 10^5$

Solution

不妨先考虑令 $ans = s_1$,跑一遍,找出每一个串与 $ans$ 的最大差距 $\Delta$ 和这个串的编号 $id$。

如果 $\Delta \le 2$,直接输出 $ans$ 就好了。

如果 $\Delta > 4$,必然无解。

现在只剩下 $\Delta = 3, 4$ 的情况。

后者是容易解决的,因为 $s_1, s_{id}$ 与真正的答案必然各有 $2$ 个不同。那么对于 $s_1$ 和 $s_{id}$ 不同的 $4$ 个位置,枚举其中哪两个是和 $s_1$ 一样,哪两个是和 $s_{id}$ 一样,剩下的 $m - 4$ 个位置必然与它们都相同,只需要检查至多 $\binom{4}{2} = 6$ 遍就行了。

着重研究一下 $\Delta = 3$ 的情况。

设真正的答案与 $s_1$ 差距为 $a$,真正的答案与 $s_{id}$ 差距为 $b$。因为 $s_1$ 和 $s_{id}$ 已经有 $3$ 个位置不同,所以 $a+b \ge 3$。同时,因为 $a \le 2, b \le 2$,所以 $a+b \le 4$。由此可知,$a+b \in \{ 3, 4 \}$。

记 $s_1$ 与 $s_{id}$ 不同的三个位置为 $x, y, z$。可不可能存在另一个 $p \notin \{x, y, z\}$,使得 $s_1/s_{id}$ 不同于真正的答案呢?

这是 不可能 的,因为如果存在这样的 $p$,必然导致 $a+b \ge 2 + 3 = 5$,矛盾。

现在考虑 $S = \{ans_x, ans_y, ans_z\}$ 分别应该是什么。

因为 $s_1$ 和 $s_{id}$ 有 $3$ 个位置不同,可知 $S$ 中必然有一个元素与 $s_1$ 对应位置相同,$S$ 中也必然有另一个元素与 $s_{id}$ 对应位置相同。这是显然的,因为不这样会导致 $a/b \ge 3$。

不失一般性的,设 $ans_x = s_{1, x}$,$ans_y = s_{id, y}$,这时候可以先随便设 $ans_z = s_{1, z}$,跑一遍,如果发现了另一个串 $id'$ 与现在的 $ans$ 有 $3$ 个不同,就可以令 $ans_z = s_{id', z}$,再检查一遍就行了。

上述过程枚举 $x, y$ 有 $\binom{3}{2} \binom{2}{1} = 6$ 种情况,每种情况至多检查 $2$ 遍,运算量接近 $12nm$。

综上,时间复杂度 $O(knm)$,$k \le 12$。为了偷懒,我下面代码写得比较丑(做了些不必要的检查),运算量可以达到 $18nm$,但这依然不影响通过此题。

#include <bits/stdc++.h>
using namespace std;
const int N = 2.5e5 + 5;
vector<int> s[N], ans;
int n, m;
void Print()
{
    cout << "Yes\n";
    for(int i = 1; i <= m; i++)
        cout << ans[i] << ' ';
}
int Comp(int idx)
{
    int res = 0;
    for(int i = 1; i <= m; i++)
    {
        if(s[idx][i] != ans[i]) res++;
    }
    return res;
}
int Comp(int idx, vector<int> &pos)
{
    int res = 0;
    pos.clear();
    for(int i = 1; i <= m; i++)
    {
        if(s[idx][i] != ans[i])
        {
            res++;
            pos.push_back(i);
        }
    }
    return res;
}
void Work(int &max_dif, int &pos)
{
    max_dif = -1;
    for(int i = 1; i <= n; i++)
    {
        int cur_dif = Comp(i);
        if(cur_dif > max_dif)
        {
            max_dif = cur_dif;
            pos = i;
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
    {
        s[i].resize(m + 5);
        for(int j = 1; j <= m; j++)
            cin >> s[i][j];
    }
    ans = s[1];
    int mx, line;
    Work(mx, line);
    if(mx <= 2)
    {
        Print();
        return 0;
    }
    else if(mx == 3)
    {
        vector<int> dif_pos;
        Comp(line, dif_pos);
        for(int chg = 1; chg < 7; chg++)
        {
            ans = s[1];
            for(int i = 0; i < 3; i++)
            {
                if(chg >> i & 1) ans[dif_pos[i]] = s[line][dif_pos[i]];
            }
            int new_mx, new_line;
            Work(new_mx, new_line);
            if(new_mx <= 2)
            {
                Print();
                return 0;
            }
            else if(new_mx == 3)
            {
                vector<int> new_dif_pos;
                Comp(new_line, new_dif_pos);
                for(int i = 0; i < 3; i++)
                {
                    int tmp = ans[new_dif_pos[i]];
                    ans[new_dif_pos[i]] = s[new_line][new_dif_pos[i]];
                    int final_mx, final_line;
                    Work(final_mx, final_line);
                    if(final_mx <= 2)
                    {
                        Print();
                        return 0;
                    }
                    ans[new_dif_pos[i]] = tmp;
                }
            }
        }
    }
    else if(mx == 4)
    {
        vector<int> dif_pos;
        Comp(line, dif_pos);
        for(int chg = 1; chg < 15; chg++)
        {
            ans = s[1];
            for(int i = 0; i < 4; i++)
            {
                if(chg >> i & 1) ans[dif_pos[i]] = s[line][dif_pos[i]];
            }
            int new_mx, new_line;
            Work(new_mx, new_line);
            if(new_mx <= 2)
            {
                Print();
                return 0;
            }
        }
    }
    cout << "No\n";
    return 0;
}
posted @ 2021-02-24 14:00  syksykCCC  阅读(70)  评论(0编辑  收藏  举报