1015 Letter-moving Game (35 分)
解题思路:
难度不大,这题花的时间并不长,码量也算是顶级较小的了,关键在于找到解题思路。
题目让你每次从s中选一个字符放到头或者尾,可以理解为经过若干次最优操作后,除了没被选中的字符,其他字符进行了一个重排。也就是说,如果s中的一个子序列与t中的一个子串是相同的,那么这个子序列是可以不需要移动的,只需要移动其他字符即可实现把s还原为t。又因为题目只需要输出次数,所以我们只要知道这个子序列的最长长度即可知道最短移动次数(每个字符移动一次即可,一定存在最优移动方案,但是不是本题需要考虑的内容)。
因此我们二分子序列长度(实际上是可以不需要的,为了思路的直观性多加一个logn的复杂度影响不大,不加二分也能写),然后枚举对于当前的子序列长度k,我们需要判断在s中能否找到这样长度为k的子序列使得t中存在一个于其相同的子串即可,方法很简单:枚举t中的所有子串,对每一个子串去s中找对应的子序列。
代码:
#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define mp make_pair
#define pb push_back
#define G 6.67430*1e-11
#define rd read()
#define pi 3.1415926535
using namespace std;
const ll mod = 1e9 + 7;
const int MAXN = 30000005;
const int MAX2 = 300005;
inline ll read() {
ll x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch>'9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
ll fpow(ll a, ll b)
{
ll ans = 1;
while (b)
{
if (b & 1)ans = ans * a % mod;
b >>= 1;
a = a * a % mod;
}
return ans;
}
string s, t;
bool judge(int n)
{
string sub;
for (int i = 0; i <= t.size() - n; i++)
{
sub = t.substr(i, n);
int now = 0;
int flag = 0;;
for (int j = 0; j < sub.size(); j++)
{
while (now < s.size() && s[now] != sub[j])
{
now++;
}
if (now < s.size())flag = j, now++;
}
if (flag == sub.size() - 1)
{
return true;
}
}
return false;
}
signed main()
{
cin >> s >> t;
int l = 0, r = s.size(), ans = 0;;
while (l <= r)
{
int mid = (l + r) >> 1;
if (judge(mid))
{
l = mid + 1;
ans = mid;
}
else r = mid - 1;
}
cout << s.size() - ans << endl;
return 0;
}