首页 > 其他分享 >AC自动机+DP luoguP4052 and P3311

AC自动机+DP luoguP4052 and P3311

时间:2022-10-08 16:22:53浏览次数:60  
标签:AC const int P3311 tr pos fail DP

https://www.luogu.com.cn/problem/P4052
题意: 求长度为m的小写字母组成的字符串ss中包含给定字符串集合S中任意一个为子串的ss个数。
思路: 经典的在ac自动机上跑dp的套路,长度为m的不包含S中任意子串的字符串ss的个数等价于trie图上长度为m不经过有ed标记的节点以及有fail树上的父亲不含ed标记的节点(后者避免了串s不是字典串但s的后缀是字典串这种情况)

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
#define PII pair<int, int>
//#define int long long
const int N = 1e4 + 5;
const int M = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e4+7;
const double PI = acos(-1.0);

namespace AC {
    int tr[N][26], tot;
    bool e[N]; int fail[N];
    void insert(char *s) {
        int u = 0; 
        for ( int i = 1; s[i]; ++ i ) {
            int ch = s[i] - 'A';
            if(!tr[u][ch]) tr[u][ch] = ++ tot;
            u = tr[u][ch];
        }
        e[u] = 1;
    }
    queue<int> q;
    void build() {
        for ( int i = 0; i < 26; ++ i ) {
            if(tr[0][i]) q.push(tr[0][i]);
        }
        while(q.size()) {
            int u = q.front();
            q.pop();
            for ( int i = 0; i < 26; ++ i ) {
                if(tr[u][i]) {
                    fail[tr[u][i]] = tr[fail[u]][i];
                    e[tr[u][i]] |= e[tr[fail[u]][i]];
                    //避免了串s不是字典串但s的后缀是字典串这种情况
                    q.push(tr[u][i]);
                } else {
                    tr[u][i] = tr[fail[u]][i];
                }
            }
        }
    }
}
char ss[105];
ll f[105][N];
int main() {
    IOS
    int n, m; cin >> n >> m;
    for ( int i = 1; i <= n; ++ i ) {
        cin >> (ss + 1);
        AC::insert(ss);   
    }
    AC::build();
    f[0][0] = 1;
    for ( int i = 1; i <= m; ++ i ) {
        for ( int j = 0; j <= AC::tot; ++ j) {
            for ( int k = 0; k < 26; ++ k ) {
                if(!AC::e[AC::tr[j][k]]) {
                    (f[i][AC::tr[j][k]] += f[i - 1][j]) %= mod;
                }
            }
        }
    }
    ll ans = 0;
    for ( int i = 0; i <= AC::tot; ++ i) {
        (ans += f[m][i]) %= mod;
    }
    ll res = 1;
    for (int i = 1; i <= m; ++ i) res = res * 26 % mod;
    cout << (res - ans + mod) % mod << '\n';
    return 0;
}

https://www.luogu.com.cn/problem/P3311
AC自动机与数位dp结合
注意字典串含前导零,统计的串不能含前导0
那么 有前导0在自动机上就是从0点(字典树的根)开始匹配

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false) ,cin.tie(0), cout.tie(0);
//#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
#define PII pair<int, int>
//#define int long long
const int N = 1e4 + 5;
const int M = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);

namespace AC {
    int tr[N][10], tot;
    bool e[N]; int fail[N];
    void insert(char *s) {
        int u = 0; 
        for ( int i = 1; s[i]; ++ i ) {
            int ch = s[i] - '0';
            if(!tr[u][ch]) tr[u][ch] = ++ tot;
            u = tr[u][ch];
        }
        e[u] = 1;
    }
    queue<int> q;
    void build() {
        for ( int i = 0; i < 10; ++ i ) {
            if(tr[0][i]) q.push(tr[0][i]);
        }
        while(q.size()) {
            int u = q.front();
            q.pop();
            for ( int i = 0; i < 10; ++ i ) {
                if(tr[u][i]) {
                    fail[tr[u][i]] = tr[fail[u]][i];
                    e[tr[u][i]] |= e[tr[fail[u]][i]];//
                    q.push(tr[u][i]);
                } else {
                    tr[u][i] = tr[fail[u]][i];
                }
            }
        }
    }
}
ll f[1505][1505]; int num[1505];
int dfs(int pos, int tr_pos, bool limit, bool lead) {
    if(!pos) return !lead;
    if(!limit && !lead && f[pos][tr_pos] != - 1) return f[pos][tr_pos];
    int len = limit ?  num[pos] : 9;
    int res = 0;
    for ( int i = 0; i <= len; ++ i ) {
        if(lead) {
            if(!AC::e[AC::tr[0][i]]) {
                res += dfs(pos - 1, AC::tr[0][i], limit && i == len, lead && !i);
                res %= mod;
            }
        } else {
            if(!AC::e[AC::tr[tr_pos][i]]) {
                res += dfs(pos - 1, AC::tr[tr_pos][i], limit && i == len, lead && !i);
                res %= mod;
            }
        }
    }
    if(!limit && !lead) f[pos][tr_pos] = res;
    return res;
}
char ss[1505];
int cal(string ss) {

    int n = ss.length();
    reverse(ss.begin(), ss.end());
    ss = " " + ss; 
    for ( int i = 1; i <= n; ++ i ) {
        num[i] = ss[i] - '0';
    }
    return dfs(n, 0, 1, 1);
}
int main() {
    IOS
    string n;
    int m; cin >> n >> m;
    for ( int i = 1; i <= m; ++ i ) {
       cin >> (ss + 1); AC::insert(ss); 
    }
    AC::build();
    memset(f, -1, sizeof f);
    cout << cal(n) << '\n';
    return 0;
}

标签:AC,const,int,P3311,tr,pos,fail,DP
From: https://www.cnblogs.com/muscletear/p/16769307.html

相关文章

  • AcWing算法提高课 分解质因数求组合数
    模板:intprimes[N],cnt;boolnot_prime[N];voidInit(){for(inti=2;i<N;i++){if(!not_prime[i]){primes[cnt++]=i;......
  • [Oracle] LeetCode 205 Isomorphic Strings
    Giventwostringssandt,determineiftheyareisomorphic.Twostringssandtareisomorphicifthecharactersinscanbereplacedtogett.Alloccurrence......
  • TCP与UDP的联系和区别
    TCP与UDP的区别TCP是面向连接的,UDP是面向无连接的UDP程序结构较简单TCP是面向字节流的,UDP是基于数据报的TCP保证数据正确性,UDP可能丢包TCP保证数据顺序,UDP不......
  • 2022 ICPC网络赛(二) G Good Permutation(树形DP 排列组合 建树)
    2022ICPC网络赛(二)GGoodPermutation题意:​ 现在有一个长度为n的排列,现在给出m组约束条件,请问有多少种方案满足这个约束条件。​ 约束条件:给出l,r,表示\([l,r]\)这个......
  • AQS源码深度解析之cancelAcquire方法解读
    1.背景2.源码解读调用该方法的地方 方法源码解读/***取消获取资源(异常处理时都需要用到)*方法主要功能:*1.处理当前取消节点的状态;......
  • ActiveMQ任意文件写入漏洞(CVE-2016-3088)
    搭建及运行漏洞环境:```docker-composebuilddocker-composeup-d```环境监听61616端口和8161端口,其中8161为web控制台端口,本漏洞就出现在web控制台中。访问`http://you......
  • Oracle
    数据库体系结构数据库逻辑存储结构重做日志文件一个数据库至少包含两个重做日志文件组。每一个重做日志文件成员对应一个物理文件。.LOG结尾数据块......
  • PyCharm: EOF while reading packet报错
    1.服务器上执行whereissftp-server,找到sftp-server位置 2.服务器上打开sshd_config:sudovi/etc/ssh/sshd_config把Subsystem这行替换成 Subsystem sftp找到的s......
  • Subsequence Path(图论,DP)
    题意给定\(N\)个点,\(M\)条边的无向图,边权为\(C_i\)。给定一个序列\(E=(E_1,E_2,\dots,E_K)\),其中\(E_i\)表示边的编号。路径是“好路径”当且仅当边的编号按照经过......
  • macs fan control pro for mac(电脑风扇控制必备)
    电脑风扇控制软件有没有?MacsFanControlPromac是Mac上一款非常实用的电脑风扇控制软件,能监视和控制Mac的风扇、控制风扇转速、温度传感器窗格、菜单栏图标,自动启动的......