zoukankan      html  css  js  c++  java
  • [SDOI2014]数数

    题解:

    做过ac自动机上dp的这题应该就很容易想到了

    首先在ac自动机上搞dp

    表示当前考虑了i位,在自动机的j位上

    然后转移就可以了

    考虑限制

    显然是一个数位dp

    考虑位数小于n显然满足要求

    考虑位数等于n

    令f[i][j][0/1]表示前i位,自动机j上,与限制是否重合 然后枚举转移就行了

    另外就是对于位数比它少的再做一次(否则的话有前导零可能会让答案变小)

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define N 2000
    #define mo 1000000007
    char cc[N];
    int x1[N],x2[N],c[5000][11],val[5000],fail[5000];
    int dp[1300][5000][2],cnt;
    bool tt=1;
    void insert(char *cc)
    {
      int len=strlen(cc),now=0;
      for (int i=0;i<len;i++)
      {
        int v=cc[i]-'0';
        if (!c[now][v]) c[now][v]=++cnt;
        now=c[now][v];
      }
      val[now]=1;
    }
    queue<int> q;
    void build()
    {
      for (int i=0;i<=9;i++)
        if (c[0][i]) fail[c[0][i]]=0,q.push(c[0][i]);
      while (!q.empty())
      {
        int u=q.front(); q.pop();
        for (int i=0;i<=9;i++)
        {
          if (c[u][i])
          {
            fail[c[u][i]]=c[fail[u]][i];
            q.push(c[u][i]);
          } else c[u][i]=c[fail[u]][i];
          val[c[u][i]]|=val[c[fail[u]][i]];
        }
      }
    }
    void plus2(int &x,int y)
    {
      x+=y;
      x=x%mo; 
    }
    bool pd(int x,int y)
    {
      if(x==0&&y==0) return(false);
      else return(true);
    }
    int main()
    {
      freopen("noi.in","r",stdin);
      freopen("noi.out","w",stdout);
      std::ios::sync_with_stdio(false);
      cin>>cc;
      int n,m,len=strlen(cc);
      n=len;
      for (int i=0;i<len;i++)
        x1[i]=cc[i]-'0';
      cin>>m;
      for (int i=1;i<=m;i++)
      {
        cin>>cc;
        insert(cc);
      }
      build();
      dp[0][0][0]=1;
      for (int i=0;i<=n-1;i++)
        for (int j=0;j<=cnt;j++)
       //   if (dp[i][j])
          {
            for (int k=0;k<=9;k++)
              if (!val[c[j][k]]&&(pd(i,k))) 
                plus2(dp[i+1][c[j][k]][1],dp[i][j][1]);
            for (int k=0;k<=x1[i]-1;k++)
              if (!val[c[j][k]]&&(pd(i,k)))
                plus2(dp[i+1][c[j][k]][1],dp[i][j][0]);
            if (!val[c[j][x1[i]]])
              plus2(dp[i+1][c[j][x1[i]]][0],dp[i][j][0]);
          }
      int ans=0;
      for (int i=0;i<=cnt;i++)
        plus2(ans,dp[n][i][0]),plus2(ans,dp[n][i][1]);
      memset(dp,0,sizeof(dp));
      dp[0][0][0]=1;
      for (int i=0;i<=n-2;i++)
        for (int j=0;j<=cnt;j++)
        {
           for (int k=0;k<=9;k++)
              if (!val[c[j][k]]&&(pd(i,k))) 
                plus2(dp[i+1][c[j][k]][0],dp[i][j][0]);
        }
      for (int i=1;i<=n-1;i++)
        for (int j=0;j<=cnt;j++)
          plus2(ans,dp[i][j][0]);
      cout<<ans;
      return 0;
    }
  • 相关阅读:
    HZOJ 通讯
    HZOJ 礼物
    HZOI 可怜与超市
    高二小假期集训—D5
    [BZOJ3566][SHOI2014]概率充电器
    [***]HZOI20190714 T2熟练剖分
    20190714(又一次翻车……)
    HZOI20190714 T3建造游乐场
    模板—慢速乘
    模板—十进制快速幂
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/8719188.html
Copyright © 2011-2022 走看看