codeforces 778A String Game&&汕头市队赛SRM06A

A 撕书 SRM 06

背景&&描述

        游行寺汀正在杀书。
        书总共有n页,每页都可以看作是一个小写英文字母,所以我们可以把书看成长度为n的字符串s。
        琉璃静静地在旁边看着。根据他对汀的了解,汀+1s只会撕一页。令a_{i}表示第i秒撕的是哪一页,显然a是1..n的一个排列。
        琉璃突然对s的一个非空子序列t产生了兴趣。他想知道,最多在汀撕多少页之后,t仍然是剩下的书的某个子序列。

 

输入格式

        第一行一个字符串,表示s

        第二行一个字符串,表示t

        第三行n个整数(n为s的长度),表示a

输出格式

一个整数,表示最多在汀撕多少页之后,t仍然是剩下的书的某个子序列。

样例输入

sbkitssakitsak
kisaki
1 14 13 2 6 12 9 10 5 3 8 4 7 11

样例输出

6

数据范围与约定

  • 对于100%的数据:1leq nleq 2*10^5

样例解释

6s后,剩下的书为kitsakit,此时kisaki还是书的子序列。第7s撕掉第二个k后就不是了。


我上的是我们市队赛的题面

跟codeforces的唯一区别是那个没有保证给的一定是书的子序列

把二分边界改一下就好了

这题得orz一波yy大爷

我自己根本没想出要二分

以后这种求最大最小的得往二分上面想啊

yy大爷的处理也很巧妙啊

想到要记录每个位置是哪一次删的

这样直接扫一遍就可以了

我本来还想着要去删的委屈

然后二分最后跨度为1的时候如果写在二分里面挺难处理的(起码我感觉是)

所以我直接break出来判一下就好了

#include<cstdio>
#include<cstring>
const int N=200007;
char a[N],b[N];
int t[N];
int n,m;
bool check(int x)
{
	for(int i=1,j=1;i<=n;i++)
	{
		if(t[i]<=x)	continue;
		if(a[i]==b[j])	j++;
		if(j==m+1)	return 1;
	}
	return 0;
}
int main()
{
	scanf("%s %s",a+1,b+1);
	n=strlen(a+1),m=strlen(b+1);
	int k;
	for(int i=1;i<=n;i++)	scanf("%d",&k),t[k]=i;
	int ll=0,rr=n;
	while(rr-ll>1)
	{
		int mid=(ll+rr)>>1;
//		printf("%d %d %d
",ll,rr,mid);
		if(check(mid))	ll=mid;
		else rr=mid-1;
	}
	if(check(rr))	printf("%d
",rr);
	else printf("%d
",ll);
	return 0;
}


原文地址:https://www.cnblogs.com/Brian551/p/7353010.html