zoukankan      html  css  js  c++  java
  • 编码

    题目描述

    Bob最近学习了一下二进制前缀编码的那一套理论。二进制编码是指一个由n个互不相同的二进制串s1,s2,...,sn构成的集合。而如果一套编码满足,对于任意的i≠j,si不是sj的前缀,那么我们称它为前缀编码。
    Bob发现了一张上面写有n行二进制编码的纸。但这张纸年代久远,有些字迹已经模糊不清。幸运的是,每一行至多只会有一个模糊的字符。
    Bob想知道这n行二进制编码是否有可能是一个前缀编码?

    输入

    输入第一行有一个整数n,表示编码的大小。
    接下来n行,每行一个由0,1及?组成的字符串。保证每一行至多有一个?

    输出

    如果这n个二进制编码可能是前缀编码那么你需要输出“YES”,否则输出“NO”。

    样例输入

    4
    00?
    0?00
    ?1
    1?0

    样例输出

    YES

    分析

    对于第i个字符串和第j个字符串,我们记(i_0)为把第i个字符串的问号变成0之后的字符串,(i_1)为把第i个字符串的问号变成0之后的字符串。
    如果(i_0)(j_x)的前缀,那么如果选择了(i_0)就必须选择(j_{xoplus1}),如果选择了(j_x),就必须选择(i_1),这样就转化成了一个2-SAT问题。
    我觉得难处理的是没有问号的字符串,问dy了好久...处理办法是,把这个点拆分为选择和不选,然后在2-SAT图里加上(不选 ightarrow选)这种边,非常机智了。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <stack>
    #include <cmath>
    #include <vector>
    #include <algorithm>
    #include <queue>
    using namespace std;
    const int maxn=500050;
    int ch[maxn*2][2],tot,num;
    int cur[maxn*2],bac[maxn*2];
    vector<int> G[maxn*8];
    void insert(char *s,int id) {
        int u=0;
        for(int i = 0; s[i]; ++i) {
            int c=s[i]-'0';
            if(s[i]=='?') c=(id&1);
            if(!ch[u][c]) ch[u][c]=++tot;
            u=ch[u][c];
        }
        if(!cur[u]) {
            cur[u]=++num,bac[u]=++num;
            G[id].push_back(cur[u]);
            G[bac[u]].push_back(id^1);
        }
        else {
            G[id].push_back(bac[u]);
            G[cur[u]].push_back(id^1);
            ++num;
            G[id].push_back(num),G[cur[u]].push_back(num),cur[u]=num;
            ++num;
            G[num].push_back(id^1),G[num].push_back(bac[u]),bac[u]=num;
        }
    }
    void dfs(int u,int pre1,int pre2) {
        if(cur[u]) {
            if(!pre1) pre1=cur[u],pre2=bac[u];
            else {
                G[cur[u]].push_back(pre2);
                G[pre1].push_back(bac[u]);
                ++num;
                G[pre1].push_back(num),G[cur[u]].push_back(num),pre1=num;
                ++num;
                G[num].push_back(pre2),G[num].push_back(bac[u]),pre2=num;
            }
        }
        if(ch[u][0]) dfs(ch[u][0],pre1,pre2);
        if(ch[u][1]) dfs(ch[u][1],pre1,pre2);
    }
    int n,pre[maxn*8],lowlink[maxn*8],dfs_no,sccCnt,sccno[maxn*8];
    stack<int> stk;
    void dfs(int u) {
        pre[u]=lowlink[u]=++dfs_no;
        stk.push(u);
        for(auto v:G[u]) {
            if(!pre[v]) dfs(v),lowlink[u]=min(lowlink[u],lowlink[v]);
            else if(!sccno[v]) lowlink[u]=min(lowlink[u],pre[v]);
        }
        if(pre[u]==lowlink[u]) {
            ++sccCnt;
            while(1) {
                int x=stk.top();stk.pop();
                sccno[x]=sccCnt;
                if(x==u) break;
            }
        }
    }
    char str[maxn];
    int main(int argc, char const *argv[])
    {
        scanf("%d", &n);
        num=n*2+2;
        for (int i = 1; i <= n; ++i)
        {
            scanf("%s", str);
            insert(str,i+i);
            int len=strlen(str);
            if(count(str,str+len,'?')) insert(str,i*2+1);
            else G[i*2+1].push_back(i+i);
        }
        dfs(0,0,0);
        for(int i = 1; i <= n; ++i) {
            if(!pre[i*2]) dfs(i*2);
            if(!pre[i*2+1]) dfs(i*2+1);
            if(sccno[i*2]==sccno[i*2+1]) {
                puts("NO");
                return 0;
            }
        }
        puts("YES");
        return 0;
    }
    
  • 相关阅读:
    洛谷P5113 Sabbat of the witch
    「学习笔记」洲阁筛
    【UNR #3】百鸽笼
    LOJ#6703. 小 Q 的序列
    python数组字符串还原为数组
    QGIS导入excel点数据
    QGIS统计面要素中包含的点要素数量
    gpd.read_file(),报错路径在系统文件中不存在
    QGIS平移要素
    QGIS多部件面转单部件面
  • 原文地址:https://www.cnblogs.com/sciorz/p/9491516.html
Copyright © 2011-2022 走看看