【JZOJ 4486】【GDOI 2016 Day1】第二题 最长公共子串

Description

给你两个字符串S,T
给你N个区间,S串中这些区间内的字符可以随意改变在区间中的位置。
求S,T可以达到的的最长公共子串长度。

Analysis

可以用双指针移动,我打的是dp。
f[i][j] 表示S串的第i个区间与T串的第j个字符的LCS。
预处理一堆东西,转移的话自行脑补。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,b,a) for(int i=b;i>=a;i--)
using namespace std;
const int N=2010;
struct section
{
    int l,r;
}a[102010],b[N];
int k,m,n,num,ans,sum['z'+1][N],h['z'+1][N],g[N],f[N][N];
char s[N],t[N];
bool cmp(section a,section b){return a.l<b.l || a.l==b.l && a.r<b.r;}
void pre()
{
    int k0;
    scanf("%s\n%s\n%d",t+1,s+1,&k0);
    m=strlen(t+1),n=strlen(s+1);
    fo(i,1,k0) scanf("%d %d",&a[i].l,&a[i].r),a[i].l++,a[i].r++;
    fo(i,1,n) a[++k0].l=a[k0].r=i;
    sort(a+1,a+k0+1,cmp);
    int l=a[1].l,r=a[1].r;
    a[k0+1].l=2147483647;
    fo(i,2,k0+1)
        if(r>=a[i].l) r=max(r,a[i].r);
        else b[++num].l=l,b[num].r=r,g[num]=r-l+1,l=a[i].l,r=a[i].r;
    fo(i,1,m)
    {
        fo(j,'a','z') sum[j][i]=sum[j][i-1];
        sum[t[i]][i]++;
    }
    fo(i,1,num)
        fo(j,b[i].l,b[i].r) h[s[j]][i]++;
}
void dp()
{
    fd(i,num,1)
        fd(j,m,1)
        {
            bool p=0;
            fo(k,j,min(m,j+g[i]-1))
            {
                if(sum[t[k]][k]-sum[t[k]][j-1]>h[t[k]][i])
                {
                    p=1;
                    break;
                }
                else f[i][j]++;
            }
            if(!p) f[i][j]+=f[i+1][j+g[i]];
            int len=0;
            fd(k,j-1,max(1,j-g[i-1]))
                if(sum[t[k]][j-1]-sum[t[k]][k-1]>h[t[k]][i-1]) break;
                else len++;
            ans=max(ans,f[i][j]+len);
        }
}
int main()
{
    freopen("lcs.in","r",stdin);
    freopen("lcs.out","w",stdout);
    pre();
    dp();
    printf("%d",ans);
    fclose(stdin);fclose(stdout);
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值