「SDOI2014」数数 解题报告
「SDOI2014」數數
題目描述
我們稱一個正整數 \(N\) 是幸運數,當且僅當它的十進制表示中不包含數字串集合 \(S\) 中任意一個元素作為其子串。
例如當 \(S=(\)22, 333, 0233\()\) 時,233 是幸運數,2333、20233、3223 不是幸運數。
給定 \(N\) 和 \(S\),計算不大于 \(N\) 的幸運數個數。
輸入格式
輸入的第一行包含整數 \(N\)。
接下來一行一個整數 \(M\),表示 \(S\) 中元素的數量。 接下來 \(M\) 行,每行一個數字串,表示 \(S\) 中的一個元素。
輸出格式
輸出一行一個整數,表示答案模 \(10^9+7\) 的值。
數據范圍與提示
我們以 \(l\) 表示 \(N\) 的長度,\(L\) 表示 \(S\) 中所有串長度之和。
對于所有數據,\(1 \leq l \leq 1200 ,\ 1 \leq M \leq 100 ,\ 1 \leq L \leq 1500\)。
關于多子串的東西可以想到AC自動機,可以在上面dp。
\(dp_{i,j,0/1}\)代表\(i\sim n\)位數字目前在AC自動機上匹配到節點\(j\)是否有最高位限制。
最后一位可以像數位dp那樣非常簡單的轉移,有個坑點是\(S\)中有前導\(0\),但是\(N\)中沒有。
有一種簡單的處理方法是在建完AC自動機后把邊\(ch[root][0]\)刪掉
Code:
#include <cstdio> #include <cstring> const int mod=1e9+7; const int N=1520; inline void add(int &x,int y){x=x+y>=mod?x+y-mod:x+y;} char s[N],t[N]; int ch[N][10],endro[N],fail[N],tot,q[N],l=1,r,bit[N],dp[N][N][2]; void ins() {scanf("%s",s+1);int n=strlen(s+1),now=0;for(int i=1;i<=n;i++){if(!ch[now][s[i]-'0']) ch[now][s[i]-'0']=++tot;now=ch[now][s[i]-'0'];}endro[now]=1; } void build() {for(int i=0;i<10;i++)if(ch[0][i])q[++r]=ch[0][i];while(l<=r){int now=q[l++];for(int i=0;i<10;i++){if(ch[now][i]) fail[q[++r]=ch[now][i]]=ch[fail[now]][i];else ch[now][i]=ch[fail[now]][i];}}ch[0][0]=0; } int main() {scanf("%s",t+1);int n=strlen(t+1),m;for(int i=1;i<=n;i++) bit[i]=t[n+1-i]-'0';scanf("%d",&m);for(int i=1;i<=m;i++) ins();build();dp[n+1][0][1]=1;for(int i=n+1;i>1;i--)for(int j=0;j<=tot;j++)for(int l=0;l<=1;l++)for(int k=0,u=l?bit[i-1]:9;k<=u;k++){int to=ch[j][k];if(!endro[to]) add(dp[i-1][to][l&k==bit[i-1]],dp[i][j][l]);}int ans=mod-1;for(int i=0;i<=tot;i++) add(ans,dp[1][i][0]),add(ans,dp[1][i][1]);printf("%d\n",ans);return 0; }2019.2.21
轉載于:https://www.cnblogs.com/butterflydew/p/10411119.html
總結
以上是生活随笔為你收集整理的「SDOI2014」数数 解题报告的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Django与Ajax
- 下一篇: .net core 上传文件大小限制