HDU 2243 考研路茫茫——單詞情結 AC自動機+DP+快速冪

與此題類似

http://blog.csdn.net/viphong/article/details/53039419

dp遞推一樣


在它的基礎上多了一步求前綴和


solution是加多一維累計即可


最後求一個26+26^2 + 26^3 + 26^4 ...的一個快速冪相減就算是答案


對2^64取模就是 ull即可


printf+ull 是%llu。。。。


#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
const int maxlen=200;
const int maxn=6*6;
const int all_size=26;
int trie[maxn][all_size];
int fail[maxn];
int tag[maxn];

int sz;
queue<int >Q;

const int N = 40;
const long long  mod=10000000;
struct Matrix
{
    unsigned long long mat[N][N];
} ;
Matrix unit_matrix ;
long long n ;

  int k=40;
Matrix mul(Matrix a, Matrix b) //矩陣相乘
{
    Matrix res;
    for(int i = 0; i < k; i++)
        for(int j = 0; j < k; j++)
        {
            res.mat[i][j] = 0;
            for(int t = 0; t < k; t++)
            {
                res.mat[i][j] += a.mat[i][t] * b.mat[t][j];
               // res.mat[i][j] %= mod;
            }
        }

    return res;
}

Matrix pow_matrix(Matrix a, long long m)  //矩陣快速冪
{
    Matrix res = unit_matrix;
    while(m != 0)
    {
        if(m & 1)
            res = mul(res, a);
        a = mul(a, a);
        m >>= 1;
    }
    return res;
}
struct Aho
{
    int root;
    int newnode()//靜態創建新節點
    {
        memset(trie[sz],-1,sizeof trie[sz]);
        tag[sz]=0;
        sz++;
        return sz-1;
    }
    void init()//初始化
    {
        sz=0;
        newnode();
    }
    void insert(char s[],int id)   //插入字符串構建ac自動機,構建trie樹
    {
        int len=strlen(s),p=0;;
        for (int i=0; i<len; i++)
        {
            int id=s[i]-'a';
            if (trie[p][id]==-1)
                trie[p][id]=newnode();
            p=trie[p][id];
        }
        tag[p]=id;   //結束標記
    }
    void getfail() //構建自動機fail指針
    {
        while(!Q.empty()) Q.pop();
        fail[root]=root;            //root指向root
        for (int i=0; i<all_size; i++)
        {
            if (trie[root][i]==-1)//第一個字符不存在,指向root
                trie[root][i]=root;
            else    //第一個字符的fail指針指向root
            {
                fail[trie[root][i]]=root;
                Q.push(trie[root][i]);   //並放入隊列,待bfs擴展
            }
        }
        while(!Q.empty())
        {
            int u=Q.front();    //取擴展節點
            Q.pop();
               if(tag[fail[u]])     tag[u]=1;  //***如果之前是tag,直接標記
            for (int i=0; i<all_size; i++)//遍歷所有子節點
            {
                if (trie[u][i]==-1)//如果不存在,則子節點直接指向fail[u]節點的對應子節點
                    trie[u][i]=trie[fail[u]][i];
                else     //如果存在,則該節點的fail指針指向fail[u]節點對應的子節點
                {
                    fail[trie[u][i]]=trie[fail[u]][i];
                    Q.push(trie[u][i]);     //繼續擴展
                }
            }
        }
    }

} aho;
char s[maxlen];
char name[15][55];



Matrix get(long long n)
{

    k=sz+1;
    Matrix c;
    memset(  c.mat ,0,sizeof c.mat);
    for (int i=0; i<sz; i++)
    {
        for (int j=0; j<26; j++)
        {
            if ( !tag[trie[i][j] ])
            c.mat[i][trie[i][j]]++;
        }
    }
    for (int i=0;i<=sz;i++)
        c.mat[i][sz]=1;
    Matrix ans = pow_matrix(c, n);
  //  ans=mul(ori,ans);
    return ans;
}

int main()
{
   /*  unsigned long long s=-1;
    printf("%lld\n",s);*/
    k=36+1;
    int  i, j, t;
     for(i = 0; i < k; i++)
        for(j = 0; j < k; j++)
            unit_matrix.mat[i][j] = 0;
    for(i = 0; i < k; i++)  unit_matrix.mat[i][i] = 1;
    long long  m;
    while(cin>>n>>m)
    {
        aho.init();
        for (int i=0; i<n; i++)
        {
            scanf("%s",name[i]);
            aho.insert(name[i],i+1);
        }

        aho.getfail();

        Matrix ret= get(m);
         unsigned long long ans=0;
             for (int j=0;j<=sz;j++)
                ans=(ans+ret.mat[0][j]);
        ans--;
        Matrix c,ori;
        k=2;
    //    memset(  c.mat ,0,sizeof c.mat);
     //   memset(  ori.mat ,0,sizeof ori.mat);
        c.mat[0][0]=26;
        c.mat[0][1]=0;
        c.mat[1][0]=26;
        c.mat[1][1]=1;
        ori.mat[0][0]=0;
        ori.mat[0][1]=1;
        ori.mat[1][0]=0;
        ori.mat[1][1]=0;

        c=pow_matrix(c,m);
        ori=mul(ori,c);

    unsigned long long  out=ori.mat[0][0]-ans;
    // cout<<out<<endl;  //AC
       printf("%llu\n",out );  //WA
    }
    return 0;
}
















dp遞推一樣
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章