zoukankan      html  css  js  c++  java
  • 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 imes 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$ 个位置必然与它们都相同,只需要检查至多 $inom{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 otin {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$ 有 $inom{3}{2} inom{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
    ";
        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
    ";
        return 0;
    }
  • 相关阅读:
    IOS开发教程--怎样使用点9图片
    Android studio 自己主动排版
    17 facade
    递归算法时间复杂度分析与改善
    __FUNCTION__, __LINE__ 有助于debug的宏定义
    表名在数据库中的存储大写和小写略解
    七夕节不撸代码你好意思说自己是程序员
    前端开发面试题收集(js部分)
    总体架构
    立即执行的匿名函数
  • 原文地址:https://www.cnblogs.com/syksykCCC/p/CF1492E.html
Copyright © 2011-2022 走看看