zoukankan      html  css  js  c++  java
  • 洛谷 P3311 [SDOI2014] 数数

    Description

    洛谷传送门

    Solution

    看起来像是一道数位 (dp)

    但是怎么做呢?我们可以联想到文本生成器那道题。

    这道题的思路也差不太多,就是在 (AC) 自动机上跑 (dp)

    那么如何判断一个数是否出现过集合 (s) 中的字符串呢?

    这个也很简单,我们建 (trie) 时先标记一下每个字符串最后结尾的位置,建 (fail) 指针时,考虑到 (fail) 指向的位置是最长前缀,所以

    End[x] |= End[fail[x]]
    

    记忆化搜索时,在 (trie) 上跑,向下搜。

    具体看代码吧。

    Code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #define ll long long
    
    using namespace std;
    
    const ll mod = 1e9 + 7;
    const ll N = 1600;
    char n[N], s[N];
    ll m;
    ll trie[N][27], tot;
    ll End[N], fail[N];
    ll dp[N][N][2][2];
    
    inline void insert(char s[]){
    	ll now = 0, len = strlen(s);
    	for(ll i = 0; i < len; i++){
    		ll c = s[i] - '0';
    		if(!trie[now][c]) trie[now][c] = ++tot;
    		now = trie[now][c];
    	}
    	End[now] = 1;
    }
    
    inline void build(){
    	queue <ll> q;
    	for(ll i = 0; i < 10; i++)
    		if(trie[0][i]) q.push(trie[0][i]);
    	while(!q.empty()){
    		ll now = q.front();
    		q.pop();
    		for(ll i = 0; i < 10; i++){
    			ll nxt = trie[now][i];
    			if(nxt){
    				fail[nxt] = trie[fail[now]][i];
    				End[nxt] |= End[fail[nxt]];
    				q.push(nxt);
    			}else trie[now][i] = trie[fail[now]][i];
    		}
    	}
    }
    
    inline ll dfs(ll len, ll now, ll flag, ll lim){
    	if(len <= 0) return !End[now];
    	if(End[now]) return 0;
    	if(dp[len][now][flag][lim] != -1) return dp[len][now][flag][lim];
    	ll x = lim ? n[len] - '0' : 9;
    	ll res = 0;
    	for(ll i = 0; i <= x; i++)
    		res = (res + dfs(len - 1, (flag && (!i)) ? 0 : trie[now][i], flag && (!i), lim && (n[len] - '0' == i)) + mod) % mod;
    	return dp[len][now][flag][lim] = res;
    }
    
    signed main(){
    	scanf("%s%lld", n + 1, &m);
    	for(ll i = 1; i <= m; i++){
    		scanf("%s", s);
    		insert(s);
    	}
    	build();
    	ll len = strlen(n + 1);
    	for(ll i = 1; i <= len / 2; i++)
    		swap(n[i], n[len - i + 1]);
    	memset(dp, -1, sizeof(dp));
    	printf("%lld
    ", (dfs(len, 0, 1, 1) + mod - 1) % mod);
    	return 0;
    }
    

    End

    本文来自博客园,作者:xixike,转载请注明原文链接:https://www.cnblogs.com/xixike/p/15374648.html

  • 相关阅读:
    python dict 与json的运用
    request各种请求的封装
    图片上传两种第三方库调用的封装函数
    JWT Token 生成与token的解析
    如何将windows文件传至linux
    windows 下python 环境安装
    shell的条件测试
    shell的数值运算
    shell基础认知
    cookie和代理
  • 原文地址:https://www.cnblogs.com/xixike/p/15374648.html
Copyright © 2011-2022 走看看