题意:给一些字符串的集合S和整数n,求满足
- 长度为n
- 只含charset = {'A'、'T‘、'G'、'C'}包含的字符
- 不包含S中任一字符串
的字符串的种类数。
思路:首先对S建立ac自动机,考虑向ac自动机中的每种状态后加charset中的字符,如果终态不为“接受状态”,也就是不与S中的任一字符串匹配,则将这次转移记为有效,方法数加1。这样可以建立状态之间的转移矩阵D,表示由一个状态接受1个字符后的方案数,D自乘n次,就得到了任一状态接受n个字符形成的不同字符串种类数,其中从“0”到“i”的方案都要加到答案里面。
另外,这题的模比较有意思,为100000,既不大也不小,或者说是个比较猥琐的数。对于100*100的矩阵,这样取模当然是吃不消的,方法是对每个点算完后一次性取模。时间由800ms→125ms。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
#pragma comment(linker, "/STACK:10240000") #include <map> #include <set> #include <cmath> #include <ctime> #include <deque> #include <queue> #include <stack> #include <vector> #include <cstdio> #include <string> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define X first #define Y second #define pb push_back #define mp make_pair #define all(a) (a).begin(), (a).end() #define fillchar(a, x) memset(a, x, sizeof(a)) #define fillarray(a, b) memcpy(a, b, sizeof(a)) typedef long long ll; typedef pair<int, int> pii; typedef unsigned long long ull; #ifndef ONLINE_JUDGE namespace Debug { void RI(vector<int>&a,int n){a.resize(n);for(int i=0;i<n;i++)scanf("%d",&a[i]);} void RI(){}void RI(int&X){scanf("%d",&X);}template<typename...R> void RI(int&f,R&...r){RI(f);RI(r...);}void RI(int*p,int*q){int d=p<q?1:-1; while(p!=q){scanf("%d",p);p+=d;}}void print(){cout<<endl;}template<typename T> void print(const T t){cout<<t<<endl;}template<typename F,typename...R> void print(const F f,const R...r){cout<<f<<", ";print(r...);}template<typename T> void print(T*p, T*q){int d=p<q?1:-1;while(p!=q){cout<<*p<<", ";p+=d;}cout<<endl;} } #endif // ONLINE_JUDGE template<typename T>bool umax(T&a, const T&b){return b<=a?false:(a=b,true);} template<typename T>bool umin(T&a, const T&b){return b>=a?false:(a=b,true);} const double PI = acos(-1.0); const int INF = 0x3f3f3f3f; const double EPS = 1e-14; /* -------------------------------------------------------------------------------- */ const int maxn = 107; const int mod = 100000; int N; struct Matrix { ll a[maxn][maxn]; Matrix() { for (int i = 0; i < N; i ++) { for (int j = 0; j < N; j ++) { a[i][j] = 0; } } } static Matrix unit() { Matrix ans; for (int i = 0; i < N; i ++) ans.a[i][i] = 1; return ans; } Matrix &operator * (const Matrix &that) const { static Matrix ans; for (int i = 0; i < N; i ++) { for (int j = 0; j < N; j ++) { ans.a[i][j] = 0; for (int k = 0; k < N; k ++) { ans.a[i][j] += a[i][k] * that.a[k][j]; } ans.a[i][j] %= mod; } } return ans; } static Matrix power(Matrix a, int n) { Matrix ans = unit(), buf = a; while (n) { if (n & 1) ans = ans * buf; buf = buf * buf; n >>= 1; } return ans; } }; struct AC_automaton { const static int SZ = 4; int f[maxn], last[maxn]; bool val[maxn]; int ch[maxn][SZ]; int sz; int idx(char ch) { if (ch == 'A') return 0; if (ch == 'T') return 1; if (ch == 'G') return 2; if (ch == 'C') return 3; } void init() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); } void insert(char s[]) { int u = 0; for (int i = 0; s[i]; i ++) { int c = idx(s[i]); if (!ch[u][c]) { memset(ch[sz], 0, sizeof(ch[sz])); val[sz] = 0; ch[u][c] = sz ++; } u = ch[u][c]; } val[u] = true; } void build() { queue<int> Q; f[0] = 0; for (int c = 0; c < SZ; c ++) { int u = ch[0][c]; if (u) { f[u] = 0; Q.push(u); last[u] = 0; } } while (!Q.empty()) { int r = Q.front(); Q.pop(); for (int c = 0; c < SZ; c ++) { int u = ch[r][c]; if (!u) { ch[r][c] = ch[f[r]][c]; continue; } Q.push(u); int v = f[r]; while (v && !ch[v][c]) v = f[v]; f[u] = ch[v][c]; last[u] = val[f[u]]? f[u] : last[f[u]]; } } } void solve(int m) { N = sz; Matrix ans; //Debug::print(sz); for (int i = 0; i < sz; i ++) { for (int j = 0; j < 4; j ++) { if (!val[ch[i][j]] && !last[ch[i][j]]) { ans.a[i][ch[i][j]] ++; } } } ans = Matrix::power(ans, m); int rst = 0; for (int i = 0; i < sz; i ++) { rst = (rst + ans.a[0][i]) % mod; } printf("%d ", rst); } }; AC_automaton ac; int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); #endif // ONLINE_JUDGE int n, m; char s[20]; while (cin >> n >> m) { ac.init(); for (int i = 0; i < n; i ++) { scanf("%s", s); ac.insert(s); } ac.build(); ac.solve(m); } return 0; } |