2019年 ACM/ICPC 亚洲区域赛(徐州)网络赛M.Longest subsequence(思维+贪心)

String is a very useful thing and a subsequence of the same string is equally important.

Now you have a string ss with length nn and a string tt with length mm. Find out the longest subsequence in the string ss so that the lexicographical order of this subsequence is strictly larger than tt.

Input

two integers nn, mm in the first line 

(All characters are lowercase letters)

The second line is a string ss

The third line is a string tt

  • 1 \le n,m \le 10^61≤n,m≤106

Output

Output an integer representing the longest length, otherwise output -1.

样例输入1复制

9 3
aaabbbccc
abc

样例输出1复制

6

样例输入2复制

9 3
aaabbbccc
zzz

样例输出2复制

-1

题意:

给你n,m(1<=n,m<=1e6),再给你长度分别为n,m的两个字符串s和t,求s中字典序严格大于t的子序列的最长长度。如果不存在输出-1。

思路:

作为本场我第一个看的题,最后也没过。赛后发现一个细节写错了,菜的真实。

看似字符串题,实际上只需要贪心一下。因为是子序列,我们先找到s中第一个大于t[0]的字符的位置,s从这个位置剩下的串即为初始化的答案。如果s串中所有字符严格小于t串的字符,那就是-1。然后开始维护两个指针i,j,和一个相同前缀长度num,拿s[i]和t[j]比较,如果s[i]<t[j]则忽略(即i++),若s[i]>t[j]则可以 break了(参考初始化的情况),否则找到s[i]后面第一个大于t[j]的字符的位置,设为pos,用num+n-pos更新答案。

然后num++,j++,i++,继续重复上述步骤,直到结束,判断一下i==n和j==m的情况。

对于pos的查找,我先用一个vector[i]存s串中严格大于字符i的所有字符的下标,然后二分查找即可。

(未必是最优的解法,但是可以过,欢迎提供更简洁易懂,复杂度更优的解法)

代码:

#pragma comment(linker,"/STACK:10240000,10240000") //防爆栈
#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<string>
#include<queue>
#include<vector>
#include<map>
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define dep(i,a,b) for(register int i=(a);i>=(b);i--)
using namespace std;
const int maxn=1000010;
char s[maxn],p[maxn];
int n,m,len,nxt[maxn];
int cnt,ans;
vector<int>vc[26];
vector<int>::iterator it,itt;
int main()
{
    int t,i,cas=1;//这个i坑死我了
    scanf("%d%d",&n,&m);
    scanf("%s",p);
    scanf("%s",s);
    int pos=0,ans=0,fg=0;cnt=0;
    for(;pos<n;pos++)
    {
        int nn=p[pos]-'a'-1;
        rep(j,0,nn) vc[j].push_back(pos);//比赛的时候这里写成i,WA,编译没报错,论不要乱定义变量的重要性
        if(p[pos]>=s[0]) fg=1;
        if(p[pos]>s[0])
        {
            ans=max(ans,n-pos);
        }
    }
    if(!fg) puts("-1");
    else
    {
        fg=0;
        int j=0,num=0;
        rep(i,0,n-1)
        {
            if(p[i]<s[j]) continue;
            else if(p[i]>s[j])
            {
                num+=(n-i);
                fg=1;
                break;
            }
            else
            {
                int nn=s[j]-'a';
                it=lower_bound(vc[nn].begin(),vc[nn].end(),i);
                if(it!=vc[nn].end())
                ans=max(ans,num+n-(*it));
                j++;
                num++;
                if(num+n-i-1<=ans) {fg=1;break;}
                if(j==m)
                {
                    if(i<n-1)
                    {
                        num+=(n-i-1);
                        fg=1;
                        break;
                    }
                    break;
                }
            }
        }
        if(fg) ans=max(ans,num);
        if(ans==0) puts("-1");
        else printf("%d\n",ans);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值