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;

}

O - Walk Through Squares
这题又被卡常了,写记忆化搜索T了,换成递推就A了。。

#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 newnode()
    {
        Next[L][0]=Next[L][1]=-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]=='R'?0:1);
            if(Next[now][go]==-1)
                Next[now][go]=newnode();
            now=Next[now][go];
        }
        end[now]|=idx;
    }

    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]];
            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 dp[105][105][maxn][4];
int M,N;
int solve()
{
    memset(dp,0,sizeof(dp));
    dp[0][0][0][0]=1;
    for(int i=0;i<=N;i++)
        for(int j=0;j<=M;j++)
            for(int k=0;k<ac.L;k++)
                for(int sta=0;sta<4;sta++)
                if(dp[i][j][k][sta])
    {
        int node1=ac.Next[k][0];
        int node2=ac.Next[k][1];
        dp[i][j+1][node1][sta|ac.end[node1]]+=dp[i][j][k][sta];
        dp[i+1][j][node2][sta|ac.end[node2]]+=dp[i][j][k][sta];
        dp[i][j+1][node1][sta|ac.end[node1]]%=mod;
        dp[i+1][j][node2][sta|ac.end[node2]]%=mod;
    }
    int ans=0;
    for(int i=0;i<=ac.L;i++)
        (ans+=dp[N][M][i][3])%=mod;
    return ans;
}

int main()
{

    int T;
    scanf("%d",&T);
    while(T--)
    {
        ac.init();
        memset(dp,0,sizeof(dp));

        scanf("%d %d",&M,&N);
        char s[105];
        scanf("%s",s);
        ac.insert(s,1);
        scanf("%s",s);
        ac.insert(s,2);
        ac.build();
        printf("%d\n",solve());
    }
    return 0;
}

P - 小明系列故事――女友的考验
这题还是wa了,原因是求两个点的距离是,他们的坐标相减竟然超int了,死活没找出来。。
写了个最短路来求最短距离。

#include<bits/stdc++.h>
using namespace std;
const int maxn=505;
typedef long long ll;
const double inf=3e18;
struct node
{
    int x,y;
}nodes[55];
int n,m;
struct Trie
{
    int Next[maxn][55],fail[maxn],end[maxn];
    int root,L;
    int newnode()
    {
        for(int i=0;i<n;i++)
            Next[L][i]=-1;
        end[L++]=0;
        return L-1;
    }
    void init()
    {
        L=0;
        root=newnode();
    }

    void insert(int a[],int len)
    {
        int now=root;
        for(int i=0;i<len;i++)
        {
            int go=a[i]-1;
            if(Next[now][go]==-1)
                Next[now][go]=newnode();
            now=Next[now][go];
        }
        end[now]=1;
    }
    void build()
    {
        int now=root;
        queue<int>Q;
        for(int i=0;i<n;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]];
            for(int i=0;i<n;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;
struct HeapNode
{
    int node,state;
    double dis;
    HeapNode(int _nde,int _ste,double _d):node(_nde),state(_ste),dis(_d){}
    HeapNode(){}
    bool operator<(const HeapNode &b)const
    {
        return dis>b.dis;
    }
};
double Map[55][55];
double dp[55][maxn];
bool vis[55][maxn];
double dis(int a,int b)
{
    ll x=0LL+nodes[a].x-nodes[b].x;
    ll y=0LL+nodes[a].y-nodes[b].y;
    return sqrt(0.0+x*x+y*y);
}
void pre_init()
{
    for(int i=0;i<n;i++)
        for(int j=i+1;j<n;j++)
        Map[i][j]=Map[j][i]=dis(i,j);

}
double bfs()
{
    for(int i=0;i<n;i++)for(int j=0;j<ac.L;j++)dp[i][j]=inf;
    int tmp=ac.Next[0][0];
    if(ac.end[tmp])return -1;
    memset(vis,0,sizeof(vis));
    dp[0][tmp]=0;
    priority_queue<HeapNode>Q;
    Q.push(HeapNode(0,tmp,0));
    while(!Q.empty())
    {
        HeapNode x=Q.top();Q.pop();
        int u=x.node,state=x.state;
        if(u==n-1)return x.dis;
        if(vis[u][state])continue;
        vis[u][state]=1;
        for(int i=u+1;i<n;i++)if(i!=u)
        {
            int newstate=ac.Next[state][i];
            if(ac.end[newstate])continue;
            if(dp[i][newstate]>dp[u][state]+Map[u][i])
            {
                dp[i][newstate]=dp[u][state]+Map[u][i];
                Q.push(HeapNode(i,newstate,dp[i][newstate]));
            }
        }
    }
    return -1;
}

int main()
{

    while(~scanf("%d %d",&n,&m)&&n)
    {
        ac.init();
        for(int i=0;i<n;i++)
            scanf("%d %d",&nodes[i].x,&nodes[i].y);
        pre_init();
        int k;
        int a[10];
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&k);
            for(int j=0;j<k;j++)
                scanf("%d",&a[j]);
            ac.insert(a,k);
        }
        ac.build();
        double ans=bfs();
        if(ans==-1)puts("Can not be reached!");
        else printf("%.2f\n",ans);
    }
    return 0;
}

这个专题把我心态写崩了。。无法形容自己,到底是因为菜还是什么,题目思路其实出的挺快,但就是A不了,还找不出错误。唉,再接再厉吧。

猜你喜欢

转载自blog.csdn.net/qq_34921856/article/details/79975650