hdu 4878 ZCC loves words AC自动机+中国剩余定理+快速幂

时间:2023-03-09 09:41:16
hdu 4878 ZCC loves words AC自动机+中国剩余定理+快速幂

题意就不说了。

分析:折腾好几天自己写的代码还是看了别人代码后发现几乎没什么复杂度的差别,可是就是一直超时,后来干脆照着别人写啊,一直WA,就在准备放弃干脆先写这篇博客的时候,又看了一眼WA的代码,发现一个中间变量没有取模直接爆掉了。终于AC了,做了好几天。

思路:对所有单词建立AC自动机,那么每个节点j转移到下一个节点k有方程:dp[i+1][k] =sum{dp[i][j]*Get},表示第i+1步位于k节点,并且由j节点转移过来,其中 Get =  ∏prime[i]*(len[i]+j)。 关键在于这里,结果是要对  179*173*163 取模, 而且Get函数和j有关,也就是走到了第j步,可以先将结果对179, 173, 163取模,然后利用中国剩余定理求出最终结果。

中国剩余定理,可以利用扩展欧几里得求出。我还是不知道我超时的原因,真是给跪了!!!!

别人代码也差不多4000+ms,我写的可能更搓了。

代码:

 #pragma comment(linker, "/STACK:16777216")
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
#define inf 0x0f0f0f0f
#define in freopen("data.txt", "r", stdin);
#define pb push_back using namespace std;
typedef long long LL; const int maxnode = ;
const int sigma_size = ;
int prime[maxnode], vis[]; void getPrime() {
int cnt = ;
for(int i = ; i < && cnt <= ; i++) {
if(!vis[i]) prime[++cnt] = i;
for(int j = i*i; j < ; j += i)
vis[j] = ;
}
} struct Node {
int len, n;
Node(int len, int n): len(len), n(n) {}
};
int ch[maxnode][sigma_size], sz, f[maxnode]; vector<Node> vec[maxnode];
struct Matrix {
int a[][];
} xx[], E0;;
void maMul(Matrix x, Matrix y, Matrix &res, int mod) {
for(int i = ; i < sz; i++)
for(int j = ; j < sz; j++) {
res.a[i][j] = ;
for(int k = ; k < sz; k++) {
res.a[i][j] += x.a[i][k]*y.a[k][j]%mod;
if(res.a[i][j] >= mod)
res.a[i][j] -= mod;
}
}
}
struct AC { void init() {
sz = ;
memset(ch[], , sizeof ch[]);
vec[].clear();
}
int idx(char ch) {
return ch - 'A';
}
void insert(char *s, int x) {
int u = , len = ;
for(int i = ; s[i]; i++, len++) {
int c = idx(s[i]);
if(!ch[u][c]) {
memset(ch[sz], , sizeof ch[sz]);
vec[sz].clear();
ch[u][c] = sz++;
}
u = ch[u][c];
}
vec[u].pb(Node(len, prime[x]));
}
void getFail() {
queue<int> q;
f[] = ;
for(int c = ; c < sigma_size; c++) {
int u = ch[][c];
if(u) {
f[u] = ;
q.push(u);
}
}
while(!q.empty()) {
int r = q.front();
q.pop();
for(int c = ; c < sigma_size; 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];
}
}
}
void getMat(int x, int mod) {
for(int i = ; i < sz; i++) for(int j = ; j < sz; j++) xx[x].a[i][j] = ;
for(int u = ; u < sz; u ++)
for(int c = ; c < sigma_size; c++) {
int v = ch[u][c];
int tv = v;
int res = ;
while(tv) {
for(int i = ; i < (int)vec[tv].size(); i++) {
(res *= ((LL)(vec[tv][i].len+x)*vec[tv][i].n%mod))%=mod;
}
tv = f[tv];
}
xx[x].a[v][u] += res;
if(xx[x].a[v][u] >= mod) xx[x].a[v][u] -= mod;
}
}
} solver; int N;
LL L;
int M[] = {, , };
int ans[], a[];
int exgcd(int a, int b, int &x, int &y) {
if(!b) {
x = , y = ;
return a;
} else {
int tmp = exgcd(b, a%b, y, x);
y -= (a/b)*x;
return tmp;
}
}
void powmod(Matrix x, LL n, Matrix &res, int mod) {
res = E0;
while(n) {
if(n&) maMul(res, x, res, mod);
maMul(x, x, x, mod);
n >>= ;
}
}
int solve() { solver.getFail();
int mul = , res = ; for(int i = ; i < ; i++) mul *= M[i];
for(int i = ; i < ; i++) {
a[i] = mul/M[i];
Matrix tmp1, tmp2;
tmp1 = tmp2 = E0;
LL lv = L%M[i];
for(int k = M[i]; k >= ; k--) {
solver.getMat(k, M[i]);
maMul(tmp1, xx[k], tmp1, M[i]);
if(k <= lv)
maMul(tmp2, xx[k], tmp2, M[i]);
}
powmod(tmp1, L/M[i], tmp1, M[i]);
maMul(tmp2, tmp1, tmp1, M[i]);
ans[i] = ;
for(int k = ; k < sz; k++) {
ans[i] += tmp1.a[k][];
if(ans[i] >= M[i]) ans[i] -= M[i];
}
int xx, yy;
exgcd(a[i], M[i], xx, yy);
res += a[i]*ans[i]%mul*(xx%M[i])%mul;
if(res >= mul)
res -= mul;
}
return (res+mul)%mul;
}
int main() { getPrime();
int kase = ; for(int i = ; i < ; i++) for(int j = ; j < ; j++) E0.a[i][j] = i == j; while(scanf("%d%I64d", &N, &L) == ) {
solver.init();
for(int i = ; i <= N; i++) {
char s[];
scanf("%s", s);
solver.insert(s, i);
}
// printf("%d\n", sz);
printf("Case #%d: %d\n", ++kase, solve());
}
return ;
}