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

    [SDOI2014]数数

    这题是AC自动机与各种dp相结合的范例。

    首先,按照套路,我们建出自动AC机。然后,因为是(le N)的所有数的总数,很容易想到数位dp(实际上它如果是在(L,R)之间所有数的总数则更明显)。

    (f_{x,len,lim})表示:

    在自动机上(x)号节点,

    匹配到了母串的(len)位置,

    当前贴上限的状态(lim)(true)为贴着)

    我们很轻易就能得出转移的记忆化:

    int dfs(int x,int len,bool lim){
    	if(!t[x].ok)return 0;
    	if(len==S)return 1;
    	if(f[x][len][lim]!=-1)return f[x][len][lim];
    	int res=0;
    	for(int i=0;i<=(lim?s[len]-'0':9);i++)res=(res+dfs(t[x].ch[i],len+1,lim&&(i==s[len]-'0')))%mod;
    	return f[x][len][lim]=res;
    }
    

    但是,兴冲冲地交上去后,你就会发现:(color{Green}_{80})

    (QaQ?)

    考虑一组数据:

    10
    1
    01
    

    如果你的程序跑出来是(9),恭喜你,上钩了!

    (01)并不是(1)的字串。

    因此我们还要再定义一维前导零状态(lead)

    状态:(f_{x,len,lim,lead})

    在自动机上(x)号节点,

    匹配到了母串的(len)位置,

    当前贴上限的状态(lim)(true)为贴着)

    前导零状态((true)为有)

    则新记忆化状态:

    int dfs(int x,int len,bool lim,bool lead){
    	if(!t[x].ok)return 0;
    	if(len==S)return 1;
    	if(f[x][len][lim][lead]!=-1)return f[x][len][lim][lead];
    	int res=0;
    	for(int i=0;i<=(lim?s[len]-'0':9);i++){
    		if(lead)res=(res+dfs(t[1].ch[i],len+1,lim&&(i==s[len]-'0'),lead&!i))%mod;
    		else res=(res+dfs(t[x].ch[i],len+1,lim&&(i==s[len]-'0'),0))%mod;
    	}
    	return f[x][len][lim][lead]=res;
    }
    

    可以看到,如果有前导零,则直接暴力从根节点开始转移。

    总代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int mod=1e9+7;
    int n,m,S,cnt=1,f[1510][1210][2][2];
    char s[1210],ss[1510];
    struct AC_Automaton{
    	int ch[10],fail;
    	bool ok;
    }t[1510];
    void ins(){
    	int x=1;
    	for(int i=0;i<S;i++){
    		if(!t[x].ch[ss[i]-'0'])t[x].ch[ss[i]-'0']=++cnt,t[cnt].ok=true;
    		x=t[x].ch[ss[i]-'0'];
    	}
    	t[x].ok=false;
    }
    queue<int>q;
    void build(){
    	for(int i=0;i<10;i++){
    		if(t[1].ch[i])t[t[1].ch[i]].fail=1,q.push(t[1].ch[i]);
    		else t[1].ch[i]=1;
    	}
    	while(!q.empty()){
    		int x=q.front();q.pop();
    		for(int i=0;i<10;i++){
    			if(t[x].ch[i])t[t[x].ch[i]].fail=t[t[x].fail].ch[i],q.push(t[x].ch[i]);
    			else t[x].ch[i]=t[t[x].fail].ch[i];
    		}
    		t[x].ok&=t[t[x].fail].ok;
    	}
    }
    int dfs(int x,int len,bool lim,bool lead){
    	if(!t[x].ok)return 0;
    	if(len==S)return 1;
    	if(f[x][len][lim][lead]!=-1)return f[x][len][lim][lead];
    	int res=0;
    	for(int i=0;i<=(lim?s[len]-'0':9);i++){
    		if(lead)res=(res+dfs(t[1].ch[i],len+1,lim&&(i==s[len]-'0'),lead&!i))%mod;
    		else res=(res+dfs(t[x].ch[i],len+1,lim&&(i==s[len]-'0'),0))%mod;
    	}
    	return f[x][len][lim][lead]=res;
    }
    int main(){
    	scanf("%s",s),n=strlen(s),t[1].ok=true,memset(f,-1,sizeof(f));
    	scanf("%d",&m);
    	for(int i=0;i<m;i++)scanf("%s",ss),S=strlen(ss),ins();
    	build();
    	S=n;
    	printf("%d
    ",(dfs(1,0,1,1)-1+mod)%mod);
    	return 0;
    }
    
  • 相关阅读:
    操作系统-进程(1)进程与进程调度
    算法-图(6)广度优先遍历图
    网络摄像头RTSP流媒体协议视频平台EasyNVR如何进行延迟测试?
    【方案搭建】如何通过RTSP协议视频平台EasyNVR架设智慧城市实景终端展现方案?
    【解决方案】如何通过RTSP流媒体协议视频平台EasyNVR搭建智慧景区远程视频监管平台?
    7-12 排序 (25分)
    7-36 社交网络图中结点的“重要性”计算 (30分)-floyd最短路径
    7-35 城市间紧急救援 (25分)-dijkstra最短路径
    7-34 任务调度的合理性 (25分)--拓扑排序
    7-33 地下迷宫探索 (30分)--DFS
  • 原文地址:https://www.cnblogs.com/Troverld/p/12781189.html
Copyright © 2011-2022 走看看