HDU 6103 Kirinriki(尺取)

本文介绍了一道关于字符串匹配的算法题目,任务是在给定的字符串中找出两个非重叠子串,使它们之间的特定距离不超过预设限制,并求解这两个子串的最大可能长度。文章提供了问题的定义、输入输出格式示例及一种基于滑动窗口技术的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Kirinriki

Problem Description

We define the distance of two strings A and B with same length n is
disA,B=∑i=0n−1|Ai−Bn−1−i|
The difference between the two characters is defined as the difference in ASCII.
You should find the maximum length of two non-overlapping substrings in given string S, and the distance between them are less then or equal to m.


Input

The first line of the input gives the number of test cases T; T test cases follow.
Each case begins with one line with one integers m : the limit distance of substring.
Then a string S follow.

Limits
T≤100
0≤m≤5000
Each character in the string is lowercase letter, 2≤|S|≤5000
∑|S|≤20000

Output

For each test case output one interge denotes the answer : the maximum length of the substring.

Sample Input

1
5
abcdefedcb

Sample Output

5

Hint

[0, 4] abcde
[5, 9] fedcb
The distance between them is abs('a' - 'b') + abs('b' - 'c') + abs('c' - 'd') + abs('d' - 'e') + abs('e' - 'f') = 5

Source

2017 Multi-University Training Contest - Team 6


题意:给出一个字符串,从中选取两个不重复的子串,使得dis距离小于等于m,输出最长子串的长度。


题解:类似处理回文串,枚举中心点(要分奇数偶数两种情况枚举),进行尺取,向外延伸,如果超过了m,去掉中心处位置。双指针维护。同时记录最大子串长度。时间复杂度O(n^2) 


#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<math.h>
#define INF 5e9;
using namespace std;
char s[5005];
int get(int i,int j)
{
    if(s[i]-s[j]<0)
        return s[j]-s[i];
    else return s[i]-s[j];
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int m;
        scanf("%d",&m);
        scanf("%s",s);
        int n=strlen(s);
        int ans=0;
        for(int i=0;i<n;i++)
        {
            int l=i,r=i;
            int ll=i,rr=i;
            int sum=0;
            while(1)
            {
                sum+=get(l,r);
                while(sum>m&&ll>=l&&rr<=r)
                {
                    sum-=get(ll,rr);
                    ll--;
                    rr++;
                }
                if(rr==i) ans=max(r-rr,ans);
                else ans=max(r-rr+1,ans);
                if(l==0||r==n-1) break;
                l--;r++;
                
            }

        }
        for(int i=0;i<n-1;i++)
        {
            int l=i,r=i+1;
            int ll=i,rr=i+1;
            int sum=0;
            while(1)
            {
                sum+=get(l,r);
                while(sum>m&&ll>=l&&rr<=r)
                {
                    sum-=get(ll,rr);
                    ll--;
                    rr++;
                }
                ans=max(r-rr+1,ans);
                if(l==0||r==n-1) break;
                l--;r++;
                
            }

        }
        cout<<ans<<endl;

    }
    return  0;
}


### HDU1565 方格数 动态规划 解题思路 对于给定的一个 \( n \times n \) 的棋盘,其中每个格子内含有一个非负数值。目标是从这些格子里选一些数,使得任何两个被选中的数所在的位置没有公共边界(即它们不是上下左右相邻),并且使选出的数之和尽可能大。 #### 构建状态转移方程 为了实现这一目的,可以定义二维数组 `dp` 来存储到达某位置的最大累积值: - 设 `dp[i][j]` 表示当考虑到第 i 行 j 列时能够获得的最大价值。 初始化阶段,设置第一行的数据作为基础情况处理;之后通过遍历整个矩阵来更新每一个可能的状态。具体来说,在计算某个特定单元 `(i, j)` 处的结果之前,应该先考察其上方以及左上角、右上角三个方向上的元素是否已经被访问过,并据此调整当前节点所能达到的最佳得分[^1]。 ```cpp for (int i = 0; i < N; ++i){ for (int j = 0; j < M; ++j){ dp[i][j] = grid[i][j]; // 上面一排的情况 if(i > 0 && !conflict(i,j,i-1,j)) dp[i][j] = max(dp[i][j], dp[i-1][j] + grid[i][j]); // 左斜线方向 if(i > 0 && j > 0 && !conflict(i,j,i-1,j-1)) dp[i][j] = max(dp[i][j], dp[i-1][j-1] + grid[i][j]); // 右斜线方向 if(i > 0 && j+1 < M && !conflict(i,j,i-1,j+1)) dp[i][j] = max(dp[i][j], dp[i-1][j+1] + grid[i][j]); } } ``` 这里需要注意的是冲突检测函数 `conflict()` ,用于判断两格之间是否存在直接连接关系。如果存在,则不允许同时选择这两格内的数字相加到路径之中去。 #### 寻找最优解 最终的答案将是最后一行中所有列的最大值之一,因为这代表了从起点出发直到终点结束可以获得的最大收益。可以通过简单的循环找到这个最大值并返回它作为结果输出。 ```cpp // 找到最后一行的最大值 __int64 result = 0; for(int col = 0; col < M; ++col) { result = max(result, dp[N-1][col]); } cout << "Maximum sum is: " << result << endl; ``` 上述方法利用了动态规划的思想有效地解决了该问题,时间复杂度大约为 O(n*m),空间复杂度同样决于输入规模大小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值