A 撕书 SRM 06
背景&&描述
游行寺汀正在杀书。
书总共有n页,每页都可以看作是一个小写英文字母,所以我们可以把书看成长度为n的字符串s。
琉璃静静地在旁边看着。根据他对汀的了解,汀+1s只会撕一页。令表示第i秒撕的是哪一页,显然是1..n的一个排列。
琉璃突然对s的一个非空子序列t产生了兴趣。他想知道,最多在汀撕多少页之后,t仍然是剩下的书的某个子序列。
输入格式
第一行一个字符串,表示s
第二行一个字符串,表示t
第三行n个整数(n为s的长度),表示。
输出格式
一个整数,表示最多在汀撕多少页之后,t仍然是剩下的书的某个子序列。
样例输入
sbkitssakitsak kisaki 1 14 13 2 6 12 9 10 5 3 8 4 7 11
样例输出
6
数据范围与约定
- 对于100%的数据:
样例解释
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; }