AC自动机专题——F - Censored! POJ - 1625 大数+DP+AC自动机

The alphabet of Freeland consists of exactly N letters. Each sentence of Freeland language (also known as Freish) consists of exactly M letters without word breaks. So, there exist exactly N^M different Freish sentences. 

But after recent election of Mr. Grass Jr. as Freeland president some words offending him were declared unprintable and all sentences containing at least one of them were forbidden. The sentence S contains a word W if W is a substring of S i.e. exists such k >= 1 that S[k] = W[1], S[k+1] = W[2], ...,S[k+len(W)-1] = W[len(W)], where k+len(W)-1 <= M and len(W) denotes length of W. Everyone who uses a forbidden sentence is to be put to jail for 10 years. 

Find out how many different sentences can be used now by freelanders without risk to be put to jail for using it. 
Input
The first line of the input file contains three integer numbers: N -- the number of letters in Freish alphabet, M -- the length of all Freish sentences and P -- the number of forbidden words (1 <= N <= 50, 1 <= M <= 50, 0 <= P <= 10). 

The second line contains exactly N different characters -- the letters of the Freish alphabet (all with ASCII code greater than 32). 

The following P lines contain forbidden words, each not longer than min(M, 10) characters, all containing only letters of Freish alphabet. 
Output
Output the only integer number -- the number of different sentences freelanders can safely use.
Sample Input
2 3 1
ab
bb
Sample Output
5


其与E题基本类似,只是输入方式不一样,这里不再赘述。

Status Accepted
Time 1266ms
Memory 5124kB
Length 11640
Lang G++
Submitted
Shared
RemoteRunId 16867314
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define rep(i,m,n) for(int i=m;i<=n;i++)
#define rsp(it,s) for(set::iterator it=s.begin();it!=s.end();it++)
const int inf_int = 2e9;
const long long inf_ll = 2e18;
#define inf_add 0x3f3f3f3f
#define MOD 1000000007
#define pb push_back
//#define mp make_pair
#define fi first
#define se second
#define pi acos(-1.0)
#define pii pair
#define Lson L, mid, rt<<1
#define Rson mid+1, R, rt<<1|1
const int maxn=5e2+10;
using namespace std;
typedef  vector vi;
typedef  long long ll;
typedef  unsigned long long  ull;
inline int read(){int ra,fh;char rx;rx=getchar(),ra=0,fh=1;
while((rx<'0'||rx>'9')&&rx!='-')rx=getchar();if(rx=='-')
fh=-1,rx=getchar();while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,
rx=getchar();return ra*fh;}
//#pragma comment(linker, "/STACK:102400000,102400000")
ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
ll qpow(ll p,ll q){ll f=1;while(q){if(q&1)f=f*p;p=p*p;q>>=1;}return f;}


int dir[8][2]={{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1}};

map mp;



#define MAX_L 205 //最大长度,可以修改
class bign
{
public:
    int len, s[MAX_L];//数的长度,记录数组
//构造函数
    bign();
    bign(const char*);
    bign(int);
    bool sign;//符号 1正数 0负数
    string toStr() const;//转化为字符串,主要是便于输出
    friend istream& operator>>(istream &,bign &);//重载输入流
    friend ostream& operator<<(ostream &,bign &);//重载输出流
//重载复制
    bign operator=(const char*);
    bign operator=(int);
    bign operator=(const string);
//重载各种比较
    bool operator>(const bign &) const;
    bool operator>=(const bign &) const;
    bool operator<(const bign &) const;
    bool operator<=(const bign &) const;
    bool operator==(const bign &) const;
    bool operator!=(const bign &) const;
//重载四则运算
    bign operator+(const bign &) const;
    bign operator++();
    bign operator++(int);
    bign operator+=(const bign&);
    bign operator-(const bign &) const;
    bign operator--();
    bign operator--(int);
    bign operator-=(const bign&);
    bign operator*(const bign &)const;
    bign operator*(const int num)const;
    bign operator*=(const bign&);
    bign operator/(const bign&)const;
    bign operator/=(const bign&);
//四则运算的衍生运算
    bign operator%(const bign&)const;//取模(余数)
    bign factorial()const;//阶乘
    bign Sqrt()const;//整数开根(向下取整)
    bign pow(const bign&)const;//次方
//一些乱乱的函数
    void clean();
    ~bign();
};
#define max(a,b) a>b ? a : b
#define min(a,b) a>(istream &in, bign &num)
{
    string str;
    in>>str;
    num=str;
    return in;
}

ostream &operator<<(ostream &out, bign &num)
{
    out<= 0; i--)
        if (s[i] != num.s[i])
            return sign ? (s[i] < num.s[i]) : (!(s[i] < num.s[i]));
    return !sign;
}

bool bign::operator>(const bign&num)const
{
    return num < *this;
}

bool bign::operator<=(const bign&num)const
{
    return !(*this>num);
}

bool bign::operator>=(const bign&num)const
{
    return !(*this num || *this < num;
}

bool bign::operator==(const bign&num)const
{
    return !(num != *this);
}

bign bign::operator+(const bign &num) const
{
    if (sign^num.sign)
    {
        bign tmp = sign ? num : *this;
        tmp.sign = 1;
        return sign ? *this - tmp : num - tmp;
    }
    bign result;
    result.len = 0;
    int temp = 0;
    for (int i = 0; temp || i < (max(len, num.len)); i++)
    {
        int t = s[i] + num.s[i] + temp;
        result.s[result.len++] = t % 10;
        temp = t / 10;
    }
    result.sign = sign;
    return result;
}

bign bign::operator++()
{
    *this = *this + 1;
    return *this;
}

bign bign::operator++(int)
{
    bign old = *this;
    ++(*this);
    return old;
}

bign bign::operator+=(const bign &num)
{
    *this = *this + num;
    return *this;
}

bign bign::operator-(const bign &num) const
{
    bign b=num,a=*this;
    if (!num.sign && !sign)
    {
        b.sign=1;
        a.sign=1;
        return b-a;
    }
    if (!b.sign)
    {
        b.sign=1;
        return a+b;
    }
    if (!a.sign)
    {
        a.sign=1;
        b=bign(0)-(a+b);
        return b;
    }
    if (a= 0) g = 0;
        else
        {
            g = 1;
            x += 10;
        }
        result.s[result.len++] = x;
    }
    result.clean();
    return result;
}

bign bign::operator * (const bign &num)const
{
    bign result;
    result.len = len + num.len;

    for (int i = 0; i < len; i++)
        for (int j = 0; j < num.len; j++)
            result.s[i + j] += s[i] * num.s[j];

    for (int i = 0; i < result.len; i++)
    {
        result.s[i + 1] += result.s[i] / 10;
        result.s[i] %= 10;
    }
    result.clean();
    result.sign = !(sign^num.sign);
    return result;
}

bign bign::operator*(const int num)const
{
    bign x = num;
    bign z = *this;
    return x*z;
}
bign bign::operator*=(const bign&num)
{
    *this = *this * num;
    return *this;
}

bign bign::operator /(const bign&num)const
{
    bign ans;
    ans.len = len - num.len + 1;
    if (ans.len < 0)
    {
        ans.len = 1;
        return ans;
    }

    bign divisor = *this, divid = num;
    divisor.sign = divid.sign = 1;
    int k = ans.len - 1;
    int j = len - 1;
    while (k >= 0)
    {
        while (divisor.s[j] == 0) j--;
        if (k > j) k = j;
        char z[MAX_L];
        memset(z, 0, sizeof(z));
        for (int i = j; i >= k; i--)
            z[j - i] = divisor.s[i] + '0';
        bign dividend = z;
        if (dividend < divid) { k--; continue; }
        int key = 0;
        while (divid*key <= dividend) key++;
        key--;
        ans.s[k] = key;
        bign temp = divid*key;
        for (int i = 0; i < k; i++)
            temp = temp * 10;
        divisor = divisor - temp;
        k--;
    }
    ans.clean();
    ans.sign = !(sign^num.sign);
    return ans;
}

bign bign::operator/=(const bign&num)
{
    *this = *this / num;
    return *this;
}

bign bign::operator%(const bign& num)const
{
    bign a = *this, b = num;
    a.sign = b.sign = 1;
    bign result, temp = a / b*b;
    result = a - temp;
    result.sign = sign;
    return result;
}

bign bign::pow(const bign& num)const
{
    bign result = 1;
    for (bign i = 0; i < num; i++)
        result = result*(*this);
    return result;
}

bign bign::factorial()const
{
    bign result = 1;
    for (bign i = 1; i <= *this; i++)
        result *= i;
    return result;
}

void bign::clean()
{
    if (len == 0) len++;
    while (len > 1 && s[len - 1] == '\0')
        len--;
}

bign bign::Sqrt()const
{
    if(*this<0)return -1;
    if(*this<=1)return *this;
    bign l=0,r=*this,mid;
    while(r-l>1)
    {
        mid=(l+r)/2;
        if(mid*mid>*this)
            r=mid;
        else
            l=mid;
    }
    return l;
}

bign::~bign()
{
}






const int N = 105;
const int M = 51;

class Trie
{

public:
    int next[N][M],fail[N],end[N];
    int root,L;
    int newnode()
    {
        for(int i = 0;i < M;i++)//每一个节点对应0-128中的任意一个。
            next[L][i] = -1;
        end[L++] = -1;//表示下面没有节点 初始化,如果是记录次数,就赋0 还可以赋任意的数,
        return L-1;
    }
    void init()
    {
        L = 0;
        root = newnode();
    }
    void insert(char s[])
    {
        int len = strlen(s);
        int now = root;
        for(int i = 0;i < len;i++)
        {
            if(next[now][mp[s[i]]] == -1)
                next[now][mp[s[i]]] = newnode();
            now=next[now][mp[s[i]]];//记录其对应的节点编号
        }
        end[now]=1;//记录当前匹配单词的节点
        //end[now]++;也可以用匹配单词结束后来记录次数
    }
    void build()
    {
        queueQ;
        fail[root] = root;//根节点仍然是根节点
        for(int i = 0;i < M;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]]== 1) end[now] = 1;
            for(int i = 0;i < M;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]);//下一行继续
                }
        }
    }


    /*bool used[N];//判断其是否被查找到
    bool query(char buf[],int n,int id)
    {
        int len = strlen(buf);
        int now = root;
        memset(used,false,sizeof(used));//初始化used
        bool flag = false;
        for(int i = 0;i < len;i++)
        {
            now = next[now][buf[i]];
            int temp = now;
            while(temp != root)
            {
                if(end[temp] != -1)
                {
                    used[end[temp]] = true;//记录被匹配的信息
                    flag = true;
                }
                temp = fail[temp];
            }
        }

    }*/
};

char buf[10005];

bign dp[N][M];
int n,m,p;

Trie ac;



int main()
{
    mp.clear();
    scanf("%d %d %d",&n,&m,&p);
    scanf("%s", buf);
    for (int i = 0; i < n; i++) { mp[buf[i]] = i; }

    ac.init();
    while(p--)
    {
        scanf("%s", buf);
        ac.insert(buf);
    }

    for (int i = 0; i < ac.L; i++)
    {
        for (int j = 0; j <= m; j++)
        {
            dp[i][j] = 0;
        }
    }

    ac.build();

    dp[0][0] = 1;
    for (int i = 1; i <= m; i++)
    {
        for (int j = 0; j < ac.L; j++)
        {
            for (int k = 0; k < n; k++)
            {
                int tmp=ac.next[j][k];
                if (ac.end[tmp]==-1)
                {
                    dp[tmp][i] += dp[j][i - 1];
                }
            }
        }
    }


    bign ans1 = 0;

    for (int i = 0; i < ac.L; i++) {
        if(ac.end[i]==-1)
            ans1 += dp[i][m];
    }
    cout << ans1 << endl;
    return 0;
}




你可能感兴趣的:(ACM_AC自动机)