ASC(2)A(大数+图论DP)

Non Absorbing DFA

Time Limit: 10000/5000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)
Problem Description

      In the theory of compilers and languages finite state machines, also known as finite automata are widely used. Deterministic finite automation (DFA) is an ordered set <Σ, U, s, T, φ>where Σ is the finite set called input alphabet, U is the finite set of states, s ∈U is the initial state, T ⊂ U is the set of terminal states and φ : U × Σ → U is the transition function.

      The input of the automation is the string α over Σ. Initially the automation is in state s. Each step it reads the first character c of the input string and changes its state to φ(u, c) where u is the current state. After that the first character of the input string is removed and the step repeats. If when its input string is empty the automation is in the terminal state, it is said that it accepts the initial string α, in the other case it rejects it.

      In some cases to simplify the automation the concept of nonabsorbing edges is introduced. That is, in addition to φ the function Х : U × Σ → {0, 1} is introduced and when making a transition from some state u with some character c, the leading character is removed from the input string only if Х(u, c) = 0. If Х(u, c) = 1, the input string is kept intact and next transition is performed with the new state and the same character.

      It is said that such automation accepts some string α if after a number of steps it transits to the terminal state and the input string becomes empty.

      Your task is given the DFA with nonabsorbing edges to compute the number of strings of the given length N that it accepts.

Input

      The first line of the input file contains Σ - a subset of the English alphabet, several different small letters. Next line contains K = |U| - the number of states of the automation (1 ≤ K ≤ 1000). Let states be numbered from 1 to K. Next line contains S (1 ≤ S ≤ K) - the initial state, followed by L = |T| - the number of terminal states and then L different integer numbers ranging from 1 to K - the numbers of terminal states.

      Next K lines contain |Σ| integer numbers each and define φ. Next K lines define Х in a similar way. The last line of the input file contains N(1 ≤ N ≤ 60).

Output
      Output the only number - the number of different strings of length N over Σ that the given DFA accepts.
Sample Input
ab
2
1 1 2
2 1
1 2
0 1
0 0
3
Sample Output
2
Hint
In the given example the two strings accepted by the automation are “aaa” and “abb”.

题意:比较恶心,感觉要说一大堆还是不说了= =,当时这题也是看哭了

思路:可以将自动机看成一个有向图,将状态看成点,将字母看成边,然后按照∮矩阵给出的值转移即可

            首先要根据X[u][c]函数将图预处理,如果X[u][c]=1则沿着这条边拓展,如果形成一个环则这种走法一定不可以

            否则将该种状态的下一步直接标记为最早能走的状态(X[u1][c1]=0)

            细节看代码吧,写了递归和递推两种版本,递归还要快点

#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
         #include 
        
          using namespace std; char s[60]; int vis[1010]; int mp[1010][60]; int is[1010][60]; int flag[1010][65]; int ok[1010][65]; int k,m,n; int sz; #define MAXN 9999 #define MAXSIZE 10 #define DLEN 4 class BigNum { private: int a[25]; //可以控制大数的位数 int len; //大数长度 public: BigNum(){ len = 1;memset(a,0,sizeof(a));} //构造函数 BigNum(const int); //将一个int类型的变量转化为大数 BigNum(const char*); //将一个字符串类型的变量转化为大数 BigNum(const BigNum &); //拷贝构造函数 BigNum &operator=(const BigNum &); //重载赋值运算符,大数之间进行赋值运算 friend istream& operator>>(istream&, BigNum&); //重载输入运算符 friend ostream& operator<<(ostream&, BigNum&); //重载输出运算符 BigNum operator+(const BigNum &) const; //重载加法运算符,两个大数之间的相加运算 BigNum operator-(const BigNum &) const; //重载减法运算符,两个大数之间的相减运算 BigNum operator*(const BigNum &) const; //重载乘法运算符,两个大数之间的相乘运算 BigNum operator/(const int &) const; //重载除法运算符,大数对一个整数进行相除运算 BigNum operator^(const int &) const; //大数的n次方运算 int operator%(const int &) const; //大数对一个int类型的变量进行取模运算 bool operator>(const BigNum & T)const; //大数和另一个大数的大小比较 bool operator<(const BigNum & T) const; bool operator==(const BigNum & T) const; bool operator>(const int & t)const; //大数和一个int类型的变量的大小比较 bool operator<(const int &t) const; bool operator==(const int &t) const; void print(); //输出大数 }; BigNum dp[1010][65]; bool BigNum::operator==(const BigNum & T) const { return !(*this > T) && !(T > *this); } bool BigNum::operator==(const int &t) const { BigNum T = BigNum(t); return *this == T; } bool BigNum::operator<(const BigNum & T) const { return T > *this; } bool BigNum::operator<(const int &t) const { return BigNum(t) > *this; } BigNum::BigNum(const int b) //将一个int类型的变量转化为大数 { int c,d = b; len = 0; memset(a,0,sizeof(a)); while(d > MAXN) { c = d - (d / (MAXN + 1)) * (MAXN + 1); d = d / (MAXN + 1); a[len++] = c; } a[len++] = d; } BigNum::BigNum(const char*s) //将一个字符串类型的变量转化为大数 { int t,k,index,l,i; memset(a,0,sizeof(a)); l=strlen(s); len=l/DLEN; if(l%DLEN) len++; index=0; for(i=l-1;i>=0;i-=DLEN) { t=0; k=i-DLEN+1; if(k<0) k=0; for(int j=k;j<=i;j++) t=t*10+s[j]-'0'; a[index++]=t; } } BigNum::BigNum(const BigNum & T) : len(T.len) //拷贝构造函数 { int i; memset(a,0,sizeof(a)); for(i = 0 ; i < len ; i++) a[i] = T.a[i]; } BigNum & BigNum::operator=(const BigNum & n) //重载赋值运算符,大数之间进行赋值运算 { int i; len = n.len; memset(a,0,sizeof(a)); for(i = 0 ; i < len ; i++) a[i] = n.a[i]; return *this; } istream& operator>>(istream & in, BigNum & b) //重载输入运算符 { char ch[MAXSIZE*4]; int i = -1; in>>ch; int l=strlen(ch); int count=0,sum=0; for(i=l-1;i>=0;) { sum = 0; int t=1; for(int j=0;j<4&&i>=0;j++,i--,t*=10) { sum+=(ch[i]-'0')*t; } b.a[count]=sum; count++; } b.len =count++; return in; } ostream& operator<<(ostream& out, BigNum& b) //重载输出运算符 { int i; cout << b.a[b.len - 1]; for(i = b.len - 2 ; i >= 0 ; i--) { cout.width(DLEN); cout.fill('0'); cout << b.a[i]; } return out; } BigNum BigNum::operator+(const BigNum & T) const //两个大数之间的相加运算 { BigNum t(*this); int i,big; //位数 big = T.len > len ? T.len : len; for(i = 0 ; i < big ; i++) { t.a[i] +=T.a[i]; if(t.a[i] > MAXN) { t.a[i + 1]++; t.a[i] -=MAXN+1; } } if(t.a[big] != 0) t.len = big + 1; else t.len = big; return t; } BigNum BigNum::operator-(const BigNum & T) const //两个大数之间的相减运算 { int i,j,big; bool flag; BigNum t1,t2; if(*this>T) { t1=*this; t2=T; flag=0; } else { t1=T; t2=*this; flag=1; } big=t1.len; for(i = 0 ; i < big ; i++) { if(t1.a[i] < t2.a[i]) { j = i + 1; while(t1.a[j] == 0) j++; t1.a[j--]--; while(j > i) t1.a[j--] += MAXN; t1.a[i] += MAXN + 1 - t2.a[i]; } else t1.a[i] -= t2.a[i]; } t1.len = big; while(t1.a[t1.len - 1] == 0 && t1.len > 1) { t1.len--; big--; } if(flag) t1.a[big-1]=0-t1.a[big-1]; return t1; } BigNum BigNum::operator*(const BigNum & T) const //两个大数之间的相乘运算 { BigNum ret; int i,j,up; int temp,temp1; for(i = 0 ; i < len ; i++) { up = 0; for(j = 0 ; j < T.len ; j++) { temp = a[i] * T.a[j] + ret.a[i + j] + up; if(temp > MAXN) { temp1 = temp - temp / (MAXN + 1) * (MAXN + 1); up = temp / (MAXN + 1); ret.a[i + j] = temp1; } else { up = 0; ret.a[i + j] = temp; } } if(up != 0) ret.a[i + j] = up; } ret.len = i + j; while(ret.a[ret.len - 1] == 0 && ret.len > 1) ret.len--; return ret; } BigNum BigNum::operator/(const int & b) const //大数对一个整数进行相除运算 { BigNum ret; int i,down = 0; for(i = len - 1 ; i >= 0 ; i--) { ret.a[i] = (a[i] + down * (MAXN + 1)) / b; down = a[i] + down * (MAXN + 1) - ret.a[i] * b; } ret.len = len; while(ret.a[ret.len - 1] == 0 && ret.len > 1) ret.len--; return ret; } int BigNum::operator %(const int & b) const //大数对一个int类型的变量进行取模运算 { int i,d=0; for (i = len-1; i>=0; i--) { d = ((d * (MAXN+1))% b + a[i])% b; } return d; } BigNum BigNum::operator^(const int & n) const //大数的n次方运算 { BigNum t,ret(1); int i; if(n<0) exit(-1); if(n==0) return 1; if(n==1) return *this; int m=n; while(m>1) { t=*this; for( i=1;i<<1<=m;i<<=1) { t=t*t; } m-=i; ret=ret*t; if(m==1) ret=ret*(*this); } return ret; } bool BigNum::operator>(const BigNum & T) const //大数和另一个大数的大小比较 { int ln; if(len > T.len) return true; else if(len == T.len) { ln = len - 1; while(a[ln] == T.a[ln] && ln >= 0) ln--; if(ln >= 0 && a[ln] > T.a[ln]) return true; else return false; } else return false; } bool BigNum::operator >(const int & t) const //大数和一个int类型的变量的大小比较 { BigNum b(t); return *this>b; } void BigNum::print() //输出大数 { int i; printf("%d", a[len-1]); for (int i = len-2; i >= 0; --i) { printf("%04d", a[i]); } puts(""); } int dfs(int s,int c) { if(is[s][c]==0){ return flag[s][c]=mp[s][c]; } if(flag[s][c]!=-1){ return flag[s][c]; } flag[s][c]=0; return flag[s][c]=dfs(mp[s][c],c); } BigNum dfs1(int s,int n) { if(ok[s][n])return dp[s][n]; ok[s][n]=1; if(n==0){ BigNum tm(1); if(vis[s])return dp[s][n]=tm; else return dp[s][n]; } for(int i=1;i<=m;i++){ if(flag[s][i]==0){ continue; } dp[s][n]=dp[s][n]+dfs1(flag[s][i],n-1); } return dp[s][n]; } int main() { // int t,tt=0; // scanf("%d",&t); // while(t--) // { // ++tt; scanf("%s",s); memset(vis,0,sizeof(vis)); m=strlen(s); int S,L; scanf("%d",&k); scanf("%d%d",&S,&L); for(int i=0;i 
          
         
       
      
      
     
     
    
    
   
   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值