POI2010CHO-Hamsters

xiaruize發表於2024-04-18

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;
}