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; }