hdu 6103 Kirinriki dp+二分 或 尺取法

本文探讨了HDU6103题目中寻找两个相同长度且不重叠的连续子串的问题,通过二分查找与动态规划相结合的方法进行解答,并提供了正确的实现代码。

题目连接:hdu 6103
题意:找出整个字符串中两个相同长度,但不重叠的连续字串,求满足他们的距离小于等于m的最长长度。
二分+dp应该也是能写的,但是我错了,应该是dp没写好, 队友写的dp过了。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 5005;
char str[20005];
short int dp[MAXN][MAXN];
bool judge(int n, int x, int len)
{
    for(int i=0; i<=len-x-x; ++i)
    {
        for(int j=i+2*x-1; j<len; ++j)
        {
            if(i+x>j-x)
            {
                if(dp[i][j]<=n)
                    return true;
            }
            else
            {
                if(dp[i][j]-dp[i+x][j-x]<=n)
                    return true;
            }
        }
    }
    return false;
}
int main()
{
    int t, n;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d",&n);
        scanf(" %s", str);
        int len=strlen(str);
        //memset(dp, 0, sizeof(dp));
        int l, r;
        for(int i=0; i<len; ++i)
        {
            l=i;
            dp[i][i]=0;
            r=i+1;
            dp[l][r]=dp[l][r]+abs(str[l]-str[r]);
            l--;
            r++;
            while(l>=0&&r<len)
            {
                dp[l][r]=dp[l+1][r-1]+abs(str[l]-str[r]);
                l--, r++;
            }
        }
        for(int i=0; i<len; ++i)
        {
            l=i-1;
            r=i+1;
            while(l>=0&&r<len)
            {
                dp[l][r]=dp[l+1][r-1]+abs(str[l]-str[r]);
                l--, r++;
            }
        }
//        for(int i=0; i<len; ++i)
//        {
//            for(int j=i; j<len; ++j)
//            {
//                printf("%d%c", dp[i][j], j==len-1?'\n':' ');
//            }
//        }
        l=0, r=len;
        while(l<r)
        {
            int mid=(l+r+1)>>1;
            if(judge(n, mid, len))
                l=mid;
            else
                r=mid-1;
        }
        printf("%d\n", l);
    }
    return 0;
}

以上是错误代码。
以下为AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N = 100011;
short dp[5005][5005];
char ch[5500];
int k;
int m;
bool panduan(int l)
{
    int i,j;
    for(i=1; i+2*l-1<=k; i++)
        for(j=k; j-2*l+1>=i; j--)
        {
            if(dp[i][j]-dp[i+l][j-l]<=m)
                return true;
        }
    return false;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&m);
        scanf("%s",ch+1);
        k=strlen(ch+1);
        int i,j;
        for(i=1; i<k; i++)
            dp[i][i]=0,dp[i][i+1]=abs(ch[i]-ch[i+1]);
        for(i=3; i<=k; i++)
        {
            for(j=1; j+i-1<=k; j++)
                dp[j][j+i-1]=dp[j+1][j+i-2]+abs(ch[j]-ch[j+i-1]);
        }
        int l=0,r=k/2;
        int m;
        while(l<r)
        {
            m=(l+r+1)>>1;
            if(!panduan(m))
                r=m-1;
            else l=m;
        }
        printf("%d\n",l);
    }
    return 0;
}

看了网上写的, 感觉当时。。好傻

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 20005;
char str[MAXN];
int ans, len, m;
void solve(int x, int y)
{
    int l=0, r=0, sum=0;
    while(x-r>=0&&y+r<len)
    {
        if(sum+abs(str[x-r]-str[y+r])<=m)
        {
            sum+=abs(str[x-r]-str[y+r]);
            r++;
            ans=max(ans, r-l);
        }
        else
        {
            sum-=abs(str[y+l]-str[x-l]);
            l++;
            ans=max(ans,r-l);
        }
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d", &m);
        scanf("%s", str);
        ans=0;
        len = strlen(str);
        for(int i=0; i<len; ++i)
        {
            solve(i, i+1);
            solve(i-1,i+1);
        }
        printf("%d\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值