http://acm.scu.edu.cn/soj/problem.action?id=3030
Mウイルスの文字列は、ウイルスが含まれていない長さnの文字列のどのように多くの異なる遺伝子配列を依頼するには?
ソリューション:
すべてのウイルスは、タイヤACツリーオートマトンを挿入し、
我々はタイヤ接尾辞木のノードは、ウイルス遺伝子配列を含むマークを検討し
ポインタは、その後、現在の状態それ以外の違法なウイルスのための現在のローカル失敗サフィックスに到達したのであれば、私たちは、失敗のポインタをビルドするとき
その後、我々は状態の間で行列に到着する可能性を得ることができ、
この行列乗たびに、答えはである新しいサフィックスを追加することに代わって、私たちは、再帰を求めています
nが大きいので、あなたはすぐに電力使用を最適化することができます
最終的な答えであり、後に自身のn倍を乗じた、すべての可能な接尾辞の状態と最初の列
#include <cstdioを> する#include <CStringの> する#include <キュー> の#include <入出力ストリーム> の#define ENDL '\ n' の#defineはっ長い長 の#define ULL符号なし長い長 の#define Fiの最初 の#define SE第二 の#define融点make_pair #define PII対<整数、整数> の#define全て(X)x.begin()、x.end() の#define IO IOS :: sync_with_stdio(偽); cin.tie(0); cout.tie(0) #define担当者(II、B)のための(INT II =; II <= Bと、++ II) (INT II = bについて(B、II)当たりの#define; II> =、 - II) の#define forn(II、X)(INT II =ヘッドの[X]; II、II = E [II] .next) 名前空間stdを使用。 CONST int型MAXN = 1E4 + 10、MAXM = 2E6 + 10。 const int型INF = 0x3f3f3f3f。 constのLL MOD = 1E5; // constのダブルPI = ACOS(-1.0); int型CASN、N、M。 クラス行列{パブリック: int型、B。 ベクター<ベクトル<LL>> X。 マトリックス(INT _a = 1、INT _b = 1): (_a)、B(_B)、X(ベクトル<LL>(B)){} ボイド要素(INTのN){ A = B = N。 X =マトリックス(N、N).X。 X [i]は[I] = 1;(; iがN <I ++はiが0 = INT)のために } 空隙充填(LL XX = 0){ (I = 0 int型私は++; iが<)のための(INT J = 0; J <B; J ++)用 X [I] [J] = XX。 } 空隙充填(ベクトル<ベクトル<LL>>&Y){ X = Y; = y.size(); B = Y [0] .size()。 } 行列演算子*(行列&M){ マトリックスANS(MB)。 用(INT J = 0; J <MB; J ++)(; iが<I ++ iが0 = INT)のための ための(INT K = 0、B <K。 ans.x [I] [J] =(ans.x [I] [J] + MOD + MOD(X [i]が[K] * MX [K] [J]%))%MOD。 ANSを返します。 } 行列演算子+(行列&M){ マトリックスANS(MB)。 用(INT J = 0; J <B; J ++)のために(I ++; iは<I = 0 INT)を ans.x [I] [J] =(X [I] [J] + MX [I]を[ J] + MOD)%のMOD。 ANSを返します。 } 行列演算子- (行列&M){ マトリックスANS(MB)。 用(INT J = 0; J <B; J ++)のために(I ++; iは<I = 0 INT)を ans.x [I] [J] =(X [I] [J] -mx [I]を[ J] + MOD)%のMOD。 ANSを返します。 } マトリックスPOW(LLのP){ マトリックスANS、T; ans.element(A); t.fill(X)。 一方、(P){IF(P&1)ANS = T * ANS; Tは= Tの* tの、P >> = 1;} 戻りANS。 } }。 CONST INT CSIZE = 4、ミンク= 0。 クラスAUTOM {パブリック: #define NDノード[今] IF(nd.son [I]){ 構造体acnode {INTフラグ、息子[CSIZE]、失敗;}ノード[MAXN]。 int型のCNT; キュー<整数> QUE。 無効クリア(){ memsetの(ノード、0、はsizeofノード)。 CNT = 0; } ボイドインサート(CHAR *は、INT LEN = 0){ LEN = STRLEN(S)IF(LEN!)。 = 0になりましたint型。 担当者(I、0、lenの-1){ int型、CH = S [i]の-minc。 (!nd.son [CH])であればnd.son [CH] = ++ CNT; 今= nd.son [CH]。 } nd.flag = 1。 } )(INITを無効{ = 0今int型。 担当者(I、0、CSIZE-1)であれば(nd.son [i])とque.push(nd.son [I])。 (!que.empty()){ながら 今= que.front(); que.pop()。 担当者(I、0、CSIZE-1){ que.push(nd.son [I])。 ノード[nd.sonは[I] =失敗ノード[nd.fail] [I] .son。 }他nd.son [I] =ノード[nd.fail] [I] .son。 ノード[nd.son [I]フラグ| =ノード[ノード[nd.fail] [I] .son]フラグ。 } } } } ACAM。 チャーP [1010]。 INT {main()のIO。 LL N、M。 一方、(CIN >> M >> N){ acam.clear()。 担当者(I、1、M){ CIN >> P。 INTのL =のSTRLEN(P)。 担当者(j、0、L-1){ IF(P [j] == 'A')p [j] = 0; 他(P [j] == 'C')p [j]が1をIF =。 他(P [j] == 'G')p [j]が2をIF =。 他のp [J] = 3; } acam.insert(P、L)。 } acam.init()。 int型のMT = ACAM。 ベクター<ベクトル<LL>> _f(MT + 1、ベクトル<LL>(MT + 1))。 IF(acam.node [I] .flag)続けます。 担当者(J、0,3)であれば(!。acam.node [acam.node [i]は.son [J]]フラグ) _f [i]の[acam.node [i]は.son [J]] ++; } 行列F; f.fill(_f)。 F = f.pow(N)。 LL ANS = 0。 担当者(I、0、MT)ANS =(ANS + FX [0] [i])と%MOD。 coutの<< ANS <<てendl; } 0を返します。 }