题目描述:
我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串。
例如当S=(22,333,0233)时,233是幸运数,2333、20233、3223不是幸运数。
给定N和S,计算不大于N的幸运数个数。
题解:
trie图上数位dp。
好像很裸的样子。
代码:
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define MOD 1000000007 char lim[1250],s[1505]; int m,tot; struct Trie { int ch[12],fl,w; }tr[1505]; void trie_pic() { queue<int>q; for(int i=0;i<=9;i++) if(tr[0].ch[i]) q.push(tr[0].ch[i]); while(!q.empty()) { int u = q.front(); q.pop(); for(int i=0;i<=9;i++) { int &v = tr[u].ch[i]; if(!v) { v=tr[tr[u].fl].ch[i]; continue; } tr[v].fl=tr[tr[u].fl].ch[i]; tr[v].w|=tr[tr[v].fl].w; q.push(v); } } } int dp[2][1205][1505],ans;//0 边界以内 1 边界上 int main() { scanf("%s%d",lim+1,&m); int lm = strlen(lim+1); for(int i=1;i<=m;i++) { scanf("%s",s+1); int u=0,len=strlen(s+1); for(int j=1;j<=len;j++) { int c = s[j]-'0'; if(!tr[u].ch[c])tr[u].ch[c]=++tot; u=tr[u].ch[c]; } tr[u].w=1; } trie_pic(); for(int i=0;i<lm;i++) { for(int j=0;j<=tot;j++) { if(dp[0][i][j]) { for(int k=0;k<=9;k++) { int to = tr[j].ch[k]; if(tr[to].w)continue; (dp[0][i+1][to]+=dp[0][i][j])%=MOD; } } if(dp[1][i][j]) { for(int k=0;k<lim[i+1]-'0';k++) { int to = tr[j].ch[k]; if(tr[to].w)continue; (dp[0][i+1][to]+=dp[1][i][j])%=MOD; } int to = tr[j].ch[lim[i+1]-'0']; if(!tr[to].w)(dp[1][i+1][to]+=dp[1][i][j])%=MOD; } if(!j) { if(!i) { for(int k=1;k<lim[1]-'0';k++) { int to = tr[j].ch[k]; if(tr[to].w)continue; (dp[0][i+1][to]+=1)%=MOD; } int to = tr[j].ch[lim[1]-'0']; if(!tr[to].w)(dp[1][i+1][to]+=1)%=MOD; }else { for(int k=1;k<=9;k++) { int to = tr[j].ch[k]; if(tr[to].w)continue; (dp[0][i+1][to]+=1)%=MOD; } } } } } int ans = 0; for(int i=0;i<=tot;i++) { (ans+=(dp[0][lm][i]+dp[1][lm][i])%MOD)%=MOD; } printf("%d ",ans); return 0; }