• [CF1110H]Modest Substrings


    description

    CodeForces
    定义一个正整数(x)是合适的当且仅当(lle xle r),其中(l,rle 10^{800})
    找到一个长度为(n)的数字串,使其包含合适的数作为子串的次数最多,(nle 2000)
    如果有多解,输出字典序最小的那个。

    solution

    如果模式串的个数不多,那么直接套用AC自动机上数位dp的方法即可。
    关于这一方法可参见[SDOI2014]数数
    现在这个做法的缺陷是要放入的串太多。
    考虑简化。
    根据数位dp的思想,一个固定位数的数只要达到安全态,后面的数码可以随意选择,
    因此我们将(ge l)(le r)的达到安全态的前缀都放入(AC)自动机;
    设计(dp)状态为(f[i][u]),表示考虑了前(i)位,目前匹配到(AC)自动机的节点(u)时,已经能够匹配的子串个数。
    对于后面的随意数码,由于题目限制长度为(n),所以只需要判断其长度是否(>n-i-1)即可。

    code

    实现代码长度居然达到(3.5k)...

    #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
    ",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;
    }
    
    
  • 相关阅读:
    Linq与Lambda,神一般的工作效率
    svn和git孰优孰劣
    关于C++的***5的输出问题
    POJ 3469 Dual Core CPU(最小割)
    HDU 4259 Double Dealing
    最大流Dinic算法
    HDU 4442 Physical Examination(2012年金华赛区现场赛A题)
    int ,long , long long类型的范围
    POJ 1679 The Unique MST(判断最小生成树是否唯一)
    HDU 4280 Island Transport(网络流)
  • 原文地址:https://www.cnblogs.com/cjfdf/p/10356021.html
Copyright © 2020-2023  润新知