• 题解【RQNOJ PID497 0/1字串问题】


    [ exttt{Description} ]

    • 编程找出符合下列条件的字符串:①字符串中仅包含 0 和 1 两个字符;②字符串的长度为 n ;③字符串中不包含连续重复三次的子串。

    [ exttt{Solution} ]

    • 考虑到,将一个串延长至 (3) 倍,就成了连续重复三次的串。

    • 于是我们枚举长度在 (frac{n}{3}) 以内的所有 (0/1) 串,将其延长至 (3) 倍,插入 (AC) 自动机中,显然这样插入,所有串的总长是可以承受的,在每个串的结尾,我们给他打上 (danger) 标记,也就是说我们不能匹配到包含 (danger) 标记的任意串。

    • 考虑 (dp)

    • (f(i,j)) 表示:考虑到 (0/1) 串的前 (i) 位,在 (AC) 自动机上的节点为 (j) 时的字符串数量。

    • 采用刷表法的方式进行 (dp) ,考虑当前的节点 (j) ,若 (j)(danger) 标记,则不能计算 (j) 的贡献,否则不难得到如下转移:

    [f(i+1,Next[j][0]) +=f(i,j) ]

    [f(i+1,Next[j][1])+=f(i,j) ]

    • 最后答案即为 (sumlimits_{danger(i)= ext{false}}f(n,i))

    [ exttt{Code} ]

    #include <bits/stdc++.h>
    const long maxn = 40;
    const long times = 3;
    const long maxNode = 400000;
    
    long n;
    
    long head, last;
    long next[maxNode][2], danger[maxNode], pre[maxNode], self[maxNode], fa[maxNode];
    
    long list[maxNode + 1];
    
    long f[2][maxNode + 1], ans;
    
    void in() {
        scanf("%ld", &n);
    }
    
    void prepare() {
        long i, j, k, l, whe, now, s, t;
        for (i = 1; i <= maxNode; i++) next[i][0] = next[i][1] = danger[i] = 0;
        last = 0;
        head = 0;
        fa[0] = 0;
        for (i = 1; i <= n / 3; i++) {
            for (j = 0; j < (1 << i); j++) {
                whe = head;
                for (k = 1; k <= times; k++) {
                    for (l = 1; l <= i; l++) {
                        now = (j >> (l - 1)) & 1;
                        if (!next[whe][now]) {
                            self[next[whe][now] = ++last] = now;
                            fa[last] = whe;
                        }
                        whe = next[whe][now];
                    }
                }
                danger[whe] = 1;
            }
        }
        s = 0;
        t = 1;
        list[1] = head;
        while (s < t) {
            whe = list[++s];
            for (i = 0; i <= 1; i++)
                if (next[whe][i])
                    list[++t] = next[whe][i];
            if (fa[whe]) {
                pre[whe] = next[pre[fa[whe]]][self[whe]];
            } else
                pre[whe] = head;
        }
        for (i = 1; i <= t; i++) {
            whe = list[i];
            for (j = 0; j <= 1; j++)
                if (!next[whe][j])
                    next[whe][j] = next[pre[whe]][j];
            danger[whe] |= danger[pre[whe]];
        }
    }
    
    void dp() {
        long i, j, k, now, pre;
        for (i = 0; i <= last; i++) f[0][i] = 0;
        f[0][0] = 1;
        now = 0;
        pre = 1;
        for (i = 0; i < n; i++) {
            now = 1 - now;
            pre = 1 - pre;
            for (j = 0; j <= last; j++) f[now][j] = 0;
            for (j = 0; j <= last; j++) {
                if (!danger[j]) {
                    f[now][next[j][0]] += f[pre][j];
                    f[now][next[j][1]] += f[pre][j];
                }
            }
        }
        ans = 0;
        for (i = 0; i <= last; i++) {
            if (!danger[i]) {
                ans += f[now][i];
            }
        }
    }
    
    void work() {
        prepare();
        dp();
    }
    
    void out() {
        std::cout << ans << std::endl;
    }
    
    int main() {
        in();
        work();
        out();
        return 0;
    }
    

    [ exttt{Thanks} exttt{for} exttt{watching} ]

  • 相关阅读:
    2017.11.20 定时器与数码管
    2017.11.19 C语言基础及流水灯实现
    libcmtd.lib(exe_wwinmain.obj) : error LNK2001: 无法解析的外部符号 _wWinMain@16
    VCatlmfcincludeafx.h(24): fatal error C1189: #error: Building MFC application with /MD[d] (CRT dll version) requires MFC shared dll version. Please #define _AFXDLL or do not use /MD[d]
    VS2015解决 error C4996: 'strdup': The POSIX name for this item is deprecated.
    vs2015单元测试
    pkg-config的一些用法
    CMake快速入门
    CMake入门教程
    Ubuntu16.04下安装NVIDIA显卡驱动
  • 原文地址:https://www.cnblogs.com/cjtcalc/p/12320467.html
Copyright © 2020-2023  润新知