• bzoj3530 [SDOI2014]数数


    题目链接

    solution

    容易想到将集合中的所有串建出AC自动机。然后用(f[i][j][0/1])表示前(i)个位置是(1)否(0)为上界,第(i)个位置对应AC自动机中的(j)号点的方案数。

    转移就枚举当前位置填的数字转移即可。

    有两个需要注意的地方:

    • 如果某个位置可以通过fail指针跳到一个子串的结束节点,那么这个节点也应该被标记为结束节点。
    • 需要排除前导零的情况。可以枚举数字的起始节点来达到这个目的。

    code

    /*
    * @Author: wxyww
    * @Date:   2020-04-19 08:45:06
    * @Last Modified time: 2020-04-19 10:07:21
    */
    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<ctime>
    using namespace std;
    typedef long long ll;
    const int N = 3010,mod = 1e9 + 7;
    ll read() {
    	ll x = 0,f = 1;char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-') f = -1; c = getchar();
    	}
    	while(c >= '0' && c <= '9') {
    		x = x * 10 + c - '0'; c = getchar();
    	}
    	return x * f;
    }
    int trie[N][11],fail[N];
    char s[N],t[N];
    
    int f[N][N][2],bz[N],tot;
    void insert() {
    	int m = strlen(t + 1);
    	int now = 0;
    	for(int i = 1;i <= m;++i) {
    		int x = t[i] - '0';
    		if(!trie[now][x]) trie[now][x] = ++tot;
    		now = trie[now][x];
    	}
    	bz[now] = 1;
    }
    queue<int>q;
    void build() {
    	for(int i = 0;i < 10;++i) if(trie[0][i]) q.push(trie[0][i]);
    	while(!q.empty()) {
    		int u = q.front();q.pop();
    		for(int i = 0;i < 10;++i) {
    			if(!trie[u][i]) trie[u][i] = trie[fail[u]][i];
    			else {
    				if(bz[trie[fail[u]][i]]) bz[trie[u][i]] = 1;
    				fail[trie[u][i]] = trie[fail[u]][i],q.push(trie[u][i]);
    			}
    		}
    	}
    }
    int n;
    void upd(int &x,int y) {
    	x += y;x >= mod ? x -= mod : 0;
    }
    void dfs(int pos) {
    	if(pos == n) return;
    
    	for(int j = 1;j < 10;++j) {
    		if(bz[trie[0][j]]) continue;
    			upd(f[pos + 1][trie[0][j]][0],1);
    	}
    	for(int i = 0;i <= tot;++i) {
    		if(bz[i]) continue;
    
    		for(int j = 0;j <= 9;++j) {
    			upd(f[pos + 1][trie[i][j]][0] ,f[pos][i][0]);
    		}
    		
    		for(int j = 0;j <= s[pos + 1] - '0';++j) {
    
    			upd(f[pos + 1][trie[i][j]][j == (s[pos + 1] - '0')] , f[pos][i][1]);
    		}
    
    	}
    	dfs(pos + 1);
    }
    
    int main() {
    	// freopen("3530/4.in","r",stdin);
    	scanf("%s",s + 1);
    	n = strlen(s + 1);
    	int m = read();
    	while(m--) {
    		scanf("%s",t + 1);
    		insert();
    	}
    	build();
    
    	for(int i = 1;i < s[1] - '0';++i) f[1][trie[0][i]][0]++;
    	f[1][trie[0][s[1] - '0']][1]++;
    
    	dfs(1);
    
    	int ans = 0;
    	for(int i = 0;i <= tot;++i) {
    		if(bz[i]) continue;
    		upd(ans,(f[n][i][0] + f[n][i][1]) % mod);
    	}
    	cout<<ans % mod<<endl;
    	return 0;
    }
    
  • 相关阅读:
    eyou通用标签的调取
    eyou头部相关标签的调用
    自增标签循环+1的方法
    文章内容页相关的标签
    当前栏目有多少文章
    指定栏目最顶级栏目名称
    当前单页正文
    Python-pandas常用函数
    监控在线平台
    网页爬虫---音乐
  • 原文地址:https://www.cnblogs.com/wxyww/p/bzoj3530.html
Copyright © 2020-2023  润新知