CodeForces
定義一個正整數\(x\)是合適的當且僅當\(l\le x\le r\),其中\(l,r\le 10^{800}\)。
找到一個長度爲\(n\)的數字串,使其包含合適的數做爲子串的次數最多,\(n\le 2000\)。
若是有多解,輸出字典序最小的那個。c++
若是模式串的個數很少,那麼直接套用AC自動機上數位dp的方法便可。
關於這一方法可參見[SDOI2014]數數。
如今這個作法的缺陷是要放入的串太多。
考慮簡化。
根據數位dp的思想,一個固定位數的數只要達到安全態,後面的數碼能夠隨意選擇,
所以咱們將\(\ge l\)或\(\le r\)的達到安全態的前綴都放入\(AC\)自動機;
設計\(dp\)狀態爲\(f[i][u]\),表示考慮了前\(i\)位,目前匹配到\(AC\)自動機的節點\(u\)時,已經可以匹配的子串個數。
對於後面的隨意數碼,因爲題目限制長度爲\(n\),因此只須要判斷其長度是否\(>n-i-1\)便可。安全
實現代碼長度竟然達到\(3.5k\)...spa
#include<bits/stdc++.h> #define pb push_back #define mp make_pair #define FL "a" using namespace std; typedef long long ll; typedef long double dd; const int N=2e3+10; const int M=2e4+10; const int inf=2147483647; const dd pi=acos(-1); const ll INF=1ll<<60; inline ll read(){ ll data=0,w=1;char ch=getchar(); while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar(); if(ch=='-')w=-1,ch=getchar(); while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar(); return data*w; } inline void file(){ freopen(FL".in","r",stdin); freopen(FL".out","w",stdout); } char sl[N],sr[N]; int n,lenl,lenr,cnt,vis[M][10],fail[M],g[M][N],f[N][M]; inline void upd(int &a,int b){a=a>b?a:b;} inline void getpre(){ scanf("%s",sl+1);lenl=strlen(sl+1); scanf("%s",sr+1);lenr=strlen(sr+1); n=read(); if(lenl==lenr){ int ul,ur;ul=ur=0; for(int i=1;i<=lenl;i++) if(ul==ur){ for(int c=sl[i]-48+1;c<sr[i]-48;c++){ if(!vis[ul][c])vis[ul][c]=++cnt; g[vis[ul][c]][lenl-i]++; } if(!vis[ul][sl[i]-48])vis[ul][sl[i]-48]=++cnt; if(!vis[ur][sr[i]-48])vis[ur][sr[i]-48]=++cnt; ul=vis[ul][sl[i]-48];ur=vis[ur][sr[i]-48]; } else{ for(int c=sl[i]-48+1;c<10;c++){ if(!vis[ul][c])vis[ul][c]=++cnt; g[vis[ul][c]][lenl-i]++; } for(int c=0;c<sr[i]-48;c++){ if(!vis[ur][c])vis[ur][c]=++cnt; g[vis[ur][c]][lenr-i]++; } if(!vis[ul][sl[i]-48])vis[ul][sl[i]-48]=++cnt; if(!vis[ur][sr[i]-48])vis[ur][sr[i]-48]=++cnt; ul=vis[ul][sl[i]-48];ur=vis[ur][sr[i]-48]; } g[ul][0]++;if(ul!=ur)g[ur][0]++; } else{ int u;u=0; for(int i=1;i<=lenl;i++){ for(int c=sl[i]-48+1;c<10;c++){ if(!vis[u][c])vis[u][c]=++cnt; g[vis[u][c]][lenl-i]++; } if(!vis[u][sl[i]-48])vis[u][sl[i]-48]=++cnt; u=vis[u][sl[i]-48]; } g[u][0]++;u=0; for(int i=1;i<=lenr;i++){ for(int c=0;c<sr[i]-48;c++){ if(!vis[u][c])vis[u][c]=++cnt; g[vis[u][c]][lenr-i]++; } if(!vis[u][sr[i]-48])vis[u][sr[i]-48]=++cnt; u=vis[u][sr[i]-48]; } g[u][0]++; for(int i=lenl+1;i<lenr;i++) for(int c=1;c<10;c++){ if(!vis[0][c])vis[0][c]=++cnt; g[vis[0][c]][i-1]++; } } for(int i=0;i<=cnt;i++)vis[0][0]=0; } inline void getfail(){ static queue<int>Q;while(!Q.empty())Q.pop(); for(int c=0;c<10;c++)if(vis[0][c])Q.push(vis[0][c]); while(!Q.empty()){ int u=Q.front();Q.pop(); for(int c=0;c<10;c++){ int &v=vis[u][c]; if(v){ Q.push(v);fail[v]=vis[fail[u]][c]; for(int i=0;i<=n;i++)g[v][i]+=g[fail[v]][i]; } else v=vis[fail[u]][c]; } } for(int u=0;u<=cnt;u++) for(int i=0;i<=n;i++) g[u][i]+=g[u][i-1]; } inline void init(){ getpre(); getfail(); } bool could[N][M]; inline void solve(){ memset(f,128,sizeof(f));f[0][0]=0; for(int i=0;i<=n;i++) for(int u=0;u<=cnt;u++) if(f[i][u]>=0){ f[i][u]+=g[u][n-i]; for(int c=0;c<10;c++) upd(f[i+1][vis[u][c]],f[i][u]); } int ans=0; for(int u=0;u<=cnt;u++)upd(ans,f[n][u]); printf("%d\n",ans); for(int u=0;u<=cnt;u++)if(f[n][u]==ans)could[n][u]=1; for(int i=n-1;~i;i--) for(int u=0;u<=cnt;u++) if(f[i][u]>=0) for(int c=0;c<10;c++) if(could[i+1][vis[u][c]]&& f[i+1][vis[u][c]]==f[i][u]+g[vis[u][c]][n-i-1]){ could[i][u]=1;break; } assert(could[0][0]==1); int u=0; for(int i=0;i<n;i++) for(int c=0;c<10;c++) if(could[i+1][vis[u][c]]&&f[i+1][vis[u][c]]==f[i][u]+g[vis[u][c]][n-i-1]){ putchar(48+c);u=vis[u][c];break; } } int main() { init(); solve(); return 0; }