1. 程式人生 > >kuangbin專題十七AC自動機總結

kuangbin專題十七AC自動機總結

這個專題寫的我頭皮發麻,出現了好多小bug耗費了我好多時間,但總體看不算太難,只要把思路縷清就行了。
AC自動機的題目有兩類,一類是字串找子串個數的,另一類則是建立狀態,然後進行dp或者矩陣快速冪。
B - 病毒侵襲
這題不算太難,但有一個坑點,就是字元都是ASCII碼可見字元。
算上空格, 從32到126共95個可見字元.
不算上空格則為94個.
所以我們讀入需要用gets,而字典樹得開到126以上。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
struct Trie
{
    int
next[maxn][128],end[maxn],fail[maxn]; int root,L; int newnode() { for(int i=0; i<128; i++) next[L][i]=-1; end[L++]=0; return L-1; } void init() { L=0; root=newnode(); } void insert(char buf[],int idx) { int
len=strlen(buf); int now=root; for(int i=0; i<len; i++) { if(next[now][buf[i]]==-1) next[now][buf[i]]=newnode(); now=next[now][buf[i]]; } end[now]=idx; } void build() { int now=root; fail[root]=root; queue
<int>
Q; for(int i=0; i<128; i++) { if(next[now][i]==-1) next[now][i]=root; else { fail[next[now][i]]=root; Q.push(next[now][i]); } } while(!Q.empty()) { now=Q.front(); Q.pop(); for(int i=0; i<128; i++) { if(next[now][i]==-1) next[now][i]=next[fail[now]][i]; else { fail[next[now][i]]=next[fail[now]][i]; Q.push(next[now][i]); } } } } void Query(char buf[],set<int>&S) { int len=strlen(buf); int now=root; for(int i=0; i<len; i++) { now=next[now][buf[i]]; int temp=now; while(temp!=root) { if(end[temp]!=0) S.insert(end[temp]); temp=fail[temp]; } } } void debug() { for(int i=0; i<L; i++) { printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]); for(int j=0; j<128; j++) printf("%2d",next[i][j]); printf("]\n"); } } }; Trie ac; char s[10005]; set<int>S; int main() { int N; while(~scanf("%d",&N)) { ac.init(); getchar(); for(int i=1; i<=N; i++) { gets(s); ac.insert(s,i); } ac.build(); //ac.debug(); int q; scanf("%d",&q); getchar(); int ans=0; set<int>::iterator itor; for(int i=1; i<=q; i++) { gets(s); S.clear(); ac.Query(s,S); if(S.size()) { ans++; printf("web %d:",i); for(itor=S.begin(); itor!=S.end(); itor++) printf(" %d",*itor); puts(""); } } printf("total: %d\n",ans); } }

D - Detect the Virus
這題唯一的麻煩的一點就是進位制之間的轉換,轉換之後就是普通的ac自動機。
這題錯了好幾次,提示Segmentation Fault,一開始以為陣列開小了,結果沒想到是陣列開得太大了。。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<queue>
#include<vector>
#include<set>
using namespace std;
const int maxn=53769;
const int maxm=15010;
struct Trie
{
    int Next[maxn][260],fail[maxn],end[maxn];
    int f[maxn];
    int root,L;
    int newnode()
    {
        for(int i=0;i<256;i++)
            Next[L][i]=-1;
        end[L++]=0;
        return L-1;
    }
    void init()
    {
        L=0;
        root=newnode();
    }

    void insert(int num[],int len)
    {
        int now=root;
        for(int i=0;i<len;i++)
        {
            if(Next[now][num[i]]==-1)
                Next[now][num[i]]=newnode();
            now=Next[now][num[i]];
        }
        end[now]++;
    }

    void build()
    {
        int now=root;
        fail[root]=root;
        queue<int>Q;
        for(int i=0;i<256;i++)
        {
            if(Next[now][i]==-1)
                Next[now][i]=root;
            else
            {
                fail[Next[now][i]]=root;
                Q.push(Next[now][i]);
            }
        }

        while(!Q.empty())
        {
            now=Q.front();Q.pop();
            for(int i=0;i<256;i++)
            {
                if(Next[now][i]==-1)
                    Next[now][i]=Next[fail[now]][i];
                else
                {
                    fail[Next[now][i]]=Next[fail[now]][i];
                    Q.push(Next[now][i]);
                }
            }
        }
    }

    int Query(int num[],int len)
    {
        memset(f,0,sizeof(f));
        int res=0;
        int now=root;
        for(int i=0;i<len;i++)
        {
            now=Next[now][num[i]];
            int temp=now;
            while(temp!=root)
            {
                if(end[temp]!=0&&!f[temp])
                    res+=end[temp],f[temp]=1;
                temp=fail[temp];
            }
        }
        return res;
    }
};
Trie ac;
char s[maxm];
int getid(char s)
{

    if(s>='A'&&s<='Z')return s-'A';
    if(s>='a'&&s<='z')return s-'a'+26;
    if(s>='0'&&s<='9')return s-'0'+52;
    if(s=='+')return 62;
    return 63;
}
vector<int>V;
int ans[maxn];
int solve(char s[],int flag)
{
    V.clear();
    int len=strlen(s);
    int tmp[10];
    for(int i=0;i<len;i++)
    {
        if(s[i]=='=')break;
        int num=getid(s[i]);
        for(int j=0;j<6;j++)
        {
            tmp[j]=num%2;
            num/=2;
        }
        for(int j=5;j>=0;j--)
            V.push_back(tmp[j]);
    }

    int Size=V.size();
    int num=Size/8;
    int cnt=0;
    for(int i=0;i<num;i++)
    {
        int thenum=0;
        for(int j=8*i;j<8*i+8;j++)
            thenum=2*thenum+V[j];
        ans[cnt++]=thenum;
    }
    if(!flag)
    {
        ac.insert(ans,cnt);
        return 0;
    }
    else
    {
        return ac.Query(ans,cnt);
    }
}

int main()
{
    int N;
    while(~scanf("%d",&N))
    {
        ac.init();
        for(int i=1;i<=N;i++)
        {
            scanf("%s",s);
            solve(s,0);
        }
        //ac.Debug();
        ac.build();
        int q;
        scanf("%d",&q);
        while(q--)
        {
            scanf("%s",s);
            printf("%d\n",solve(s,1));
        }
        puts("");
    }
    return 0;
}

E - DNA Sequence
對於這題我想說明什麼時候會建立矩陣,什麼時候會dp。我們可以發現這兩種方法實際上都是狀態的轉移,而建立矩陣的時候往往步數會很多,例如這題n達到了2e9,所以不得不用矩陣,然後進行矩陣快速冪。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stdio.h>
#include<queue>
using namespace std;
const int maxn=105;
const int mod=100000;
typedef long long ll;
int tn;

struct Mat
{
    ll mat[maxn][maxn];
    Mat()
    {
        memset(mat,0,sizeof(mat));
    }
    void out()
    {
        for(int i=0; i<tn; i++)
        {
            for(int j=0; j<tn; j++)
                cout<<mat[i][j]<<" ";
            cout<<endl;
        }
    }
};

Mat operator*(const Mat &m1,const Mat &m2)
{
    Mat m;
    for(int i=0; i<tn; i++)
        for(int j=0; j<tn; j++)
            for(int k=0; k<tn; k++)
            {
                m.mat[i][j]+=(m1.mat[i][k]*m2.mat[k][j])%mod;
                m.mat[i][j]%=mod;
            }
    return m;
}

Mat quick_mul(int num,Mat a)
{
    Mat e;
    for(int i=0; i<tn; i++)
        e.mat[i][i]=1;
    while(num)
    {
        if(num%2)
            e=e*a;
        num/=2;
        a=a*a;
    }
    return e;
}

int getid(char s)
{
    if(s=='A')return 0;
    if(s=='T')return 1;
    if(s=='C')return 2;
    return 3;
}

struct Trie
{
    int Next[maxn][4],fail[maxn],end[maxn];
    int flag[maxn];
    int root,L;
    int newnode()
    {
        for(int i=0; i<4; i++)
            Next[L][i]=-1;
        end[L++]=0;
        return L-1;
    }
    void init()
    {
        memset(flag,0,sizeof(flag));
        L=0;
        root=newnode();
    }

    void insert(char buf[])
    {
        int len=strlen(buf);
        int now=root;
        for(int i=0; i<len; i++)
        {
            int id=getid(buf[i]);
            if(Next[now][id]==-1)
                Next[now][id]=newnode();
            now=Next[now][id];
        }
        end[now]++;
        flag[now]=1;
    }

    void build()
    {
        int now=root;
        fail[root]=root;
        queue<int>Q;
        for(int i=0; i<4; i++)
        {
            if(Next[now][i]==-1)
                Next[now][i]=root;
            else
            {
                fail[Next[now][i]]=root;
                Q.push(Next[now][i]);
            }
            //flag[Next[now][i]]|=flag[Next[fail[now]][i]];
        }
        while(!Q.empty())
        {
            now=Q.front();
            Q.pop();
            for(int i=0; i<4; i++)
            {
                if(Next[now][i]==-1)
                    Next[now][i]=Next[fail[now]][i];
                else
                {
                    fail[Next[now][i]]=Next[fail[now]][i];
                    Q.push(Next[now][i]);
                }
                flag[Next[now][i]]|=flag[Next[fail[now]][i]];
            }
        }
    }
    void buildmatrix(Mat &a)
    {
        for(int i=0; i<L; i++)if(!flag[i])
                for(int j=0; j<4; j++)if(!flag[Next[i][j]])
                        a.mat[i][Next[i][j]]++,a.mat[i][Next[i][j]]%=mod;
    }
};
char s[15];
Trie ac;
int main()
{
    int m,n;
    while(~scanf("%d %d",&m,&n))
    {
        ac.init();
        for(int i=1; i<=m; i++)
        {
            scanf("%s",s);
            ac.insert(s);
        }
        Mat a;
        ac.build();
        tn=ac.L;
        ac.buildmatrix(a);
        //a.out();
        Mat ans;
        ans=quick_mul(n,a);
        ll theans=0;
        for(int i=0; i<tn; i++)
            theans=(theans+ans.mat[0][i])%mod;
        printf("%lld\n",theans);
    }
return 0;
}

H - Wireless Password
這題被卡常了,怪我自己程式碼寫醜了。
兩個數的按位異或等於兩個數直接異或!

#include<bits/stdc++.h>
using namespace std;
const int mod=20090717;
const int maxn=105;
typedef long long ll;
struct Trie
{
    int Next[maxn][26],fail[maxn],end[maxn];
    int root,L;
    int newnode()
    {
        for(int i=0;i<26;i++)
            Next[L][i]=-1;
        end[L++]=0;
        return L-1;
    }
    void init()
    {
        L=0;
        root=newnode();
    }

    void insert(char s[],int idx)
    {
        int len=strlen(s);
        int now=root;
        for(int i=0;i<len;i++)
        {
            int go=s[i]-'a';
            if(Next[now][go]==-1)
                Next[now][go]=newnode();
            now=Next[now][go];
        }
        end[now]=(1<<idx);
    }
    void build()
    {
        int now=root;
        queue<int>Q;
        for(int i=0;i<26;i++)
        {
            if(Next[now][i]==-1)
                Next[now][i]=root;
            else
            {
                fail[Next[now][i]]=root;
                Q.push(Next[now][i]);
            }
        }

        while(!Q.empty())
        {
            now=Q.front();Q.pop();
            if(end[fail[now]])end[now]+=end[fail[now]];
            for(int i=0;i<26;i++)
            {
                if(Next[now][i]==-1)
                    Next[now][i]=Next[fail[now]][i];
                else
                {
                    fail[Next[now][i]]=Next[fail[now]][i];
                    Q.push(Next[now][i]);
                }
            }
        }
    }

};

Trie ac;

int dp[30][maxn][1025];
int n,m,k;
bool check(int num)
{
    int res=0;
    while(num)
    {
        res+=num%2;
        num/=2;
    }
    if(res>=k)return 1;
    return 0;
}

int main()
{

    while(~scanf("%d %d %d",&n,&m,&k)&&n)
    {
        ac.init();
        char s[15];
        for(int i=0;i<m;i++)
        {
            scanf("%s",s);
            ac.insert(s,i);
        }
        memset(dp,0,sizeof(dp));
        ac.build();
        //Matrix to=ac.buildmatrix();
        //to.out();
        dp[0][0][0]=1;
        int statenum=ac.L;
        for(int i=1;i<=n;i++)
            for(int j=0;j<statenum;j++)
                for(int kase=0;kase<(1<<m);kase++)if(dp[i-1][j][kase])
                    for(int t=0;t<26;t++)
                    {
                        int v=ac.Next[j][t];
                        if(ac.end[v]!=-1)
                        {
                            int it=ac.end[v];
                            int tmp=kase|it;
                            dp[i][v][tmp]=(dp[i][v][tmp]+dp[i-1][j][kase])%mod;
                        }
                        else
                        {
                            dp[i][v][kase]=(dp[i][v][kase]+dp[i-1][j][kase])%mod;
                        }
                    }
        int ans=0;
        for(int i=0;i<(1<<m);i++)
        {
            if(check(i))
            {
                for(int j=0;j<statenum;j++)
                    ans=(ans+dp[n][j][i])%mod;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

I - Ring
這題還是wa了好幾次,原因是不知道怎麼求字典序最小的串,最後看別人的才知道存起來就完事了。。
另外當找不到時,應該輸出空字元而不應該輸出’a’。。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1110;
typedef long long ll;
struct Trie
{
    int Next[maxn][26],fail[maxn],end[maxn];
    int root,L;
    int newnode()
    {
        for(int i=0; i<26; i++)
            Next[L][i]=-1;
        end[L++]=0;
        return L-1;
    }
    void init()
    {
        L=0;
        root=newnode();
    }

    void insert(char s[],int cost)
    {
        int now=root;
        int len=strlen(s);
        for(int i=0; i<len; i++)
        {
            int go=s[i]-'a';
            if(Next[now][go]==-1)
                Next[now][go]=newnode();
            now=Next[now][go];
        }
        end[now]+=cost;
    }

    void build()
    {
        int now=root;
        queue<int>Q;
        for(int i=0; i<26; i++)
        {
            if(Next[now][i]==-1)
                Next[now][i]=root;
            else
            {
                fail[Next[now][i]]=root;
                Q.push(Next[now][i]);
            }
        }
        while(!Q.empty())
        {
            now=Q.front();
            Q.pop();
            if(end[fail[now]])
                end[now]+=end[fail[now]];
            for(int i=0; i<26; i++)
            {
                if(Next[now][i]==-1)
                    Next[now][i]=Next[fail[now]][i];
                else
                {
                    fail[Next[now][i]]=Next[fail[now]][i];
                    Q.push(Next[now][i]);
                }
            }
        }
    }
};
Trie ac;
char s[110][15];
int cost[110];
ll dp[55][maxn];
string rout[55][maxn];

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        for(int i=0;i<55;i++)
            for(int j=0;j<maxn;j++)rout[i][j]="";
        int n,m;
        ac.init();
        scanf("%d %d",&n,&m);

        for(int i=1; i<=m; i++)
            scanf("%s",s[i]);
        for(int i=1; i<=m; i++)
            scanf("%d",&cost[i]);
        for(int i=1; i<=m; i++)
            ac.insert(s[i],cost[i]);
        ac.build();
        memset(dp,-1,sizeof(dp));
        dp[0][0]=0;
        int state=ac.L;
        ll maxcost=-1;
        int len,goodstate;
        for(int i=1; i<=n; i++)
            for(int j=0; j<state; j++)if(dp[i-1][j]!=-1)
                    for(int k=0; k<26; k++)
                    {
                        int newstate=ac.Next[j][k];
                        int thecost=ac.end[newstate];
                        if(dp[i][newstate]<dp[i-1][j]+thecost)
                        {
                            dp[i][newstate]=dp[i-1][j]+thecost;
                            char tmp=k+'a';
                            rout[i][newstate]=rout[i-1][j]+tmp;
                        }
                        else if(dp[i][newstate]==dp[i-1][j]+thecost)
                        {
                            char tmp=k+'a';
                            if(rout[i][newstate]>rout[i-1][j]+tmp)
                            {
                                rout[i][newstate]=rout[i-1][j]+tmp;
                            }
                        }
                        if(maxcost<dp[i][newstate])
                        {
                            maxcost=dp[i][newstate];
                            len=i;
                            goodstate=newstate;
                        }
                        else if(maxcost==dp[i][newstate])
                        {
                            if(rout[len][goodstate]>rout[i][newstate])
                            {
                                len=i;
                                goodstate=newstate;
                            }
                        }
                    }

        if(maxcost==0)
            puts("");
        else
        {
            cout<<rout[len][goodstate]<<endl;
        }
    }
    return 0;
}

M - Resource Archiver
先用AC自動機建好狀態,然後對於每個end不為0的節點求出它到其他節點的最短距離,然後進行dp即可。dp[i][j] 代表包含串的狀態為i,目前在的狀態為j的能組成符合題意的最短串長。

#include<bits/stdc++.h>
using namespace std;
const int maxn=60005;
const int inf=0x3f3f3f3f;
int state[15],cnt;
int d[15][15];
int dis[maxn];
struct Trie
{
    int Next[maxn][2],fail[maxn],end[maxn];
    bool virus[maxn];
    int root,L;
    int newnode()
    {
        Next[L][0]=Next[L][1]=-1;
        end[L]=0;
        virus[L++]=0;
        return L-1;
    }
    void init()
    {
        L=0;
        root=newnode();
    }
    void insert(char s[],int type)
    {
        int len=strlen(s);
        int now=root;
        for(int i=0;i<len;i++)
        {
            int go=s[i]-'0';
            if(Next[now][go]==-1)
                Next[now][go]=newnode();
            now=Next[now][go];
        }
        if(type>=0)
            end[now]|=(1<<type);
        else
            virus[now]=1;
    }
    void build()
    {
        int now=root;
        queue<int>Q;
        for(int i=0;i<2;i++)
        {
            if(Next[now][i]==-1)
                Next[now][i]=root;
            else
            {
                fail[Next[now][i]]=root;
                Q.push(Next[now][i]);
            }
        }
        while(!Q.empty())
        {
            now=Q.front();Q.pop();
            end[now]|=end[fail[now]];
            virus[now]|=virus[fail[now]];
            for(int i=0;i<2;i++)
            {
                if(Next[now][i]==-1)
                    Next[now][i]=Next[fail[now]][i];
                else
                {
                    fail[Next[now][i]]=Next[fail[now]][i];
                    Q.push(Next[now][i]);
                }
            }
        }
    }
    void buildstate()
    {
        state[0]=0;
        cnt=1;
        for(int i=0;i<L;i++)if(!virus[i]&&end[i])
            state[cnt++]=i;
    }
    void bfs(int s)
    {
        int thestate=state[s];
        queue<int>Q;
        Q.push(thestate);
        memset(dis,-1,sizeof(dis));
        dis[thestate]=0;
        while(!Q.empty())
        {
            int x=Q.front();Q.pop();
            for(int i=0;i<2;i++)
            {
                int newstate=Next[x][i];
                if(virus[newstate])continue;
                if(dis[newstate]==-1)
                {
                    dis[newstate]=dis[x]+1;
                    Q.push((newstate));
                }
            }
        }
        for(int i=0;i<cnt;i++)
            d[s][i]=dis[state[i]];
    }
    void solve()
    {
        for(int i=0;i<cnt;i++)
            bfs(i);
    }
};
Trie ac;
int dp[(1<<10)][15];
int n,m;
int dfs(int strsta,int nowsta)
{
    if(strsta==(1<<n)-1)return 0;
    if(dp[strsta][nowsta]!=inf)return dp[strsta][nowsta];
    for(int i=0;i<=cnt;i++)
    {
        if(d[nowsta][i]<0)continue;
        int newstrsta=strsta|ac.end[state[i]];
        if(newstrsta==strsta)continue;
        dp[strsta][nowsta]=min(dp[strsta][nowsta],dfs(newstrsta,i)+d[nowsta][i]);
    }
    return dp[strsta][nowsta];
}
int main()
{

    while(~scanf("%d %d",&n,&m)&&n)
    {
        char s[1005];
        ac.init();
        for(int i=0;i<n;i++)
        {
            scanf("%s",s);
            ac.insert(s,i);
        }
        for(int i=0;i<m;i++)
        {
            scanf("%s",s);
            ac.insert(s,-1);
        }
        ac.build();
        ac.buildstate();
        ac.solve();
        memset(dp,inf,sizeof(dp));
        printf("%d\n",dfs(0,0));
    }
    return 0;
}

N - BCD Code
這題思路挺好想的,可惜中間寫錯了,還找不出來。。處理A的時候應該對字元減減就行,而我卻減’1’。。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2505;
const int mod=1000000009;
struct Trie
{
    int Next[2010][2],fail[2010];
    bool end[2010];
    int root,L;
    int newnode()
    {
        for(int i = 0;i < 2;i++)
            Next[L][i] = -1;
        end[L++] = false;
        return L-1;
    }
    void init()
    {
        L = 0;
        root = newnode();
    }
    void insert(char buf[])
    {
        int len = strlen(buf);
        int now = root;
        for(int i = 0;i < len ;i++)
        {
            if(Next[now][buf[i]-'0'] == -1)
                Next[now][buf[i]-'0'] = newnode();
            now = Next[now][buf[i]-'0'];
        }
        end[now] = true;
    }
    void build()
    {
        queue<int>Q;
        fail[root] = root;
        for(int i = 0;i < 2;i++)
            if(Next[root][i] == -1)
                Next[root][i] = root;
            else
            {
                fail[Next[root][i]] = root;
                Q.push(Next[root][i]);
            }
        while(!Q.empty())
        {
            int now = Q.front();
            Q.pop();
            if(end[fail[now]])end[now] = true;
            for(int i = 0;i < 2;i++)
                if(Next[now][i] == -1)
                    Next[now][i] = Next[fail[now]][i];
                else
                {
                    fail[Next[now][i]] = Next[fail[now]][i];
                    Q.push(Next[now][i]);
                }
        }
    }
};
Trie ac;
int bcd[maxn][10];
int change(int pre,int num)
{
    if(ac.end[pre])return -1;
    int cur = pre;
    for(int i = 3;i >= 0;i--)
    {
        if(ac.end[ac.Next[cur][(num>>i)&1]])return -1;
        cur = ac.Next[cur][(num>>i)&1];
    }
    return cur;
}
void pre_init()
{
    for(int i = 0;i <ac.L;i++)
        for(int j = 0;j <10;j++)
            bcd[i][j] = change(i,j);
}

int a[210];
ll dp[210][maxn];
long long dfs(int pos,int s,bool flag,bool z)
{
    if(pos == -1)return 1;
    if(!flag && dp[pos][s]!=-1)return dp[pos][s];
    long long ans = 0;
    if(z)
    {
        ans += dfs(pos-1,s,flag && a[pos]==0,true);
        ans %= mod;
    }
    else
    {
        if(bcd[s][0]!=-1)ans += dfs(pos-1,bcd[s][0],flag && a[pos]==0,false);
        ans %= mod;
    }
    int end = flag?a[pos]:9;
    for(int i = 1;i<=end;i++)
    {
        if(bcd[s][i]!=-1)
        {
            ans += dfs(pos-1,bcd[s][i],flag&&i==end,false);
            ans %=mod;
        }
    }
    if(!flag && !z)dp[pos][s] = ans;
    return ans;
}
long long solve(char s[])
{
    int len = strlen(s);
    for(int i = 0;i < len;i++)
        a[i] = s[len-1-i]-'0';
    return dfs(len-1,0,1,1);
}
void change(char s[])
{
    int slen=strlen(s);
    for(int i=slen-1;i>=0;i--)
    {
        if(s[i]>='1')
        {
            s[i]-='1';
            break;
        }
        else
            s[i]='9';
    }
}
char str[210];
int main()
{
    int T;
    scanf("%d",&T);
    int N;
    while(T--)
    {

        ac.init();
        scanf("%d",&N);
        for(int i=1; i<=N; i++)
        {
            scanf("%s",str);
            ac.insert(str);
        }
        ac.build();
        pre_init();
        memset(dp,-1,sizeof(dp));
        int ans=0;
        scanf("%s",str);
        int len = strlen(str);
        for(int i = len -1;i >=0;i--)
        {
            if(str[i]>'0')
            {
                str[i]--;
                break;
            }
            else str[i] = '9';
        }
        ans-=solve(str);
        ans%=mod;
        scanf("%s",str);
        ans+=solve(str);
        ans%=mod;
        if(ans<0)ans+=mod;
        printf("%d\n",ans);
    }
    return 0;

}
#include<bits/stdc++.h>
using namespace std;
const int maxn=205;
const int mod=1000000007;
typedef long long ll;
struct Trie
{
    int Next[maxn][2],fail[maxn],end[maxn];
    int root,L;
    int newno