POI #Year2010 #kmp #字串 #dp #矩陣最佳化dp
用 \(kmp\) 處理兩個串拼在一起最小增加的代價,然後 \(dp_{i,j}\) 表示選擇 \(i\) 個最後是 \(j\) 的最小長度
轉移列舉拼接的串
這個明顯可以矩陣最佳化
// Author: xiaruize
const int N = 1e5 + 10;
int n, m;
string s[N];
struct Matrix
{
int mat[205][205];
Matrix() { mms(mat, 0x3f); }
Matrix operator*(Matrix b)
{
Matrix res;
rep(i, 0, n)
{
rep(j, 0, n)
{
rep(k, 0, n)
{
res.mat[i][j] = min(res.mat[i][j], mat[i][k] + b.mat[k][j]);
}
}
}
return res;
}
} mat, st;
Matrix qpow(Matrix a, int b)
{
Matrix res = st;
while (b)
{
if (b & 1)
res = res * a;
a = a * a;
b >>= 1;
}
return res;
}
int nxt[N];
int siz[N];
void solve()
{
cin >> n >> m;
rep(i, 1, n)
{
cin >> s[i];
siz[i] = s[i].size();
s[i] = " " + s[i];
}
rep(x, 1, n)
{
for (int i = 2, j = 0; i <= siz[x]; i++)
{
while (j && s[x][j + 1] != s[x][i])
j = nxt[j];
if (s[x][j + 1] == s[x][i])
j++;
nxt[i] = j;
// debug(i, nxt[i]);
}
rep(y, 1, n)
{
int j = 0;
for (int i = 2; i <= siz[y]; i++)
{
while (j && s[x][j + 1] != s[y][i])
j = nxt[j];
if (s[x][j + 1] == s[y][i])
j++;
}
mat.mat[y][x] = siz[x] - j;
debug(y, x, j, siz[x] - j);
}
}
rep(i, 1, n) st.mat[0][i] = siz[i];
st = qpow(mat, m - 1);
int res = INF;
rep(i, 1, n)
{
res = min(res, st.mat[0][i]);
debug(st.mat[0][i]);
}
cout << res << endl;
}
#ifndef ONLINE_JUDGE
bool end_of_memory_use;
#endif
signed main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int testcase = 1;
// cin >> testcase;
while (testcase--)
solve();
#ifndef ONLINE_JUDGE
cerr << "Memory use:" << (&end_of_memory_use - &start_of_memory_use) / 1024.0 / 1024.0 << "MiB" << endl;
cerr << "Time use:" << (double)clock() / CLOCKS_PER_SEC * 1000.0 << "ms" << endl;
#endif
return 0;
}