题意:
P有一个字符串t,他每次会按顺序以a1, a2...an为下标来删除t中的字符,n是t的长度。S想得到一个字符串p,保证p是t的一个子串,在P对字符串删除时,当到了合适的时候,S会过来阻止P,自己来完成删除得到想要的字符串s。问P最多能删除几个字符。
解题思路:
题目其实就是让求在保证p中有子序列s的情况下,最少能删除多少个字符串。
我一直在想着怎么优化验证p中有子序列s的算法,然而怎么也想不出。赛后问了金桔,才知道这道题优化的是验证次数啊,假如我们去二分答案,然后再验证答案的正确性,验证次数就从n降到log(n)了,虽然验证答案的复杂度仍然是n,但是合在一起的复杂度就是nlog(n)了。换个思路就能想出来了,然而没有。还是太菜啊,QAQ。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
char t[maxn];
char p[maxn];
int a[maxn];
bool book[maxn];
int n;
bool judge(int mid)
{
int i, k;
memset(book, 0, sizeof book);
for(i=1; i<=mid; i++)
{
book[a[i]]=1;
}
k=1;
for(i=1; i<=n; i++)
{
if(book[i]==0)
{
if(t[i]==p[k])k++;
if(!p[k])break;
}
}
return (i<=n);
}
int ef(int s, int d)
{
int i, mid=(s+d)/2, k=0;
while(s<d)
{
mid=(s+d)/2;
if((d-s)<=1)
{
if(judge(d))return d;
else return s;
}
if(judge(mid))
{
s=mid;
}
else d=mid-1;
}
return (s+d)/2;
}
int main()
{
scanf("%s", t+1);
scanf("%s", p+1);
int i, j;
n=strlen(t+1);
for(i=1; i<=n; i++)
{
scanf("%d", &a[i]);
}
int ans=ef(0, n);
printf("%d\n", ans);
}