题目大意:
就是给你一个字符串,让你从中选取两个不相交的子串,使得它们在差不超过 m 的前提下尽可能的长,问你最长可能的长度。两个子串的差定义为两个子串一个正向遍历一个同时反向遍历,对应位置字符差的绝对值的和。
分析:
办法就是把所给字符串 a 倒序生成字符串 b ,然后问题就转化成了如何将 a b 字符串匹配才能得到最长的符合要求的匹配长度。那么我的想法就是把 a b 字符串错位,对于每一种错位状况,我用一种类似于尺取法的办法在 O(n) 的之间内,取出可能的最大长度。那么对于大约 2*n 种错位状况,我就能在大约 O( n2 )的时间内求得该问题的解。
代码:
#include<bits/stdc++.h>
#define maxn 5050
using namespace std;
int test=0;
char a[maxn],b[maxn];
int n,m;
int main()
{
scanf("%d",&test);
while(test--)
{
scanf("%d",&m);
scanf("%s",a);
n=strlen(a);
for(int i=0;i<n;i++)
{
b[i]=a[n-i-1];
}
int ans=0;
int best=0,val=0;
for(int j=0;j<n-1;j++)
{
best=0;
val=0;
for(int i=0;i<(n-j)/2;i++)//iºÅºÍi+jºÅ±È
{
val+=abs(a[i]-b[i+j]);
if(val>m)
{
val-=abs(a[i-best]-b[i+j-best]);
continue;
}
best++;
}
if(ans<best)
{
ans=best;
}
}
for(int j=0;j<n-1;j++)
{
best=0;
val=0;
for(int i=0;i<(n-j)/2;i++)//iºÅºÍi+jºÅ±È
{
val+=abs(b[i]-a[i+j]);
if(val>m)
{
val-=abs(b[i-best]-a[i+j-best]);
continue;
}
best++;
}
if(ans<best)
{
ans=best;
}
}
printf("%d\n",ans);
}
}
总结:
第六场多校赛了,这一场自认为发挥还是不错。本来开始之前就想吃午饭,但是突然一狠心,还是不吃了,一会要是能 ac 3题就出去吃好的!没够就晚上也不吃了。结果因为怕饿一晚上还是拼命做了3题出来,刚刚吃得还挺爽。
其实感觉这三道都是说不出什么算法,就是比较靠技巧的,主要是看ac人数大概估计了题的难度,少走了好多弯路。主要是对于这一道题,想的时候,我也想到了会不会是要用 dp ,但是这次真的是脑子没敢停(实在是想吃肉了),感觉想到解法的过程是一种类似于广搜的过程,向 dp 的方向想一点,遇到困难再换成暴力的思想,遇到困难想不到的时候,又回去继续想 dp ,然后又找不到合适状态,结果又换成别的方向,反正各个方向都想了一下,但都不是很深,因为我觉得300人 ac 的题真的不应该太复杂。也许是真的有点着急了,不过还是想到了比较简单的办法。后面发现代码能力还是低,几十行的代码,边界就能想乱。(不是原理想不明白,是 i j 从零开始从一开始,奇数偶数想不过来)好在还是ac了这道“吃饭题”。激动地直接去约饭了,也没安排好~
但是感觉最关键的一步是想到要把 a 字符串倒序生成 b 然后放到一起比(虽然部分区域无法取到),如果只是想把一个字符串分两个合适的部分,而把这个问题看成是在一串数中找两个子串的合适的边界位置的话,感觉就很难想出结果了,因为这样很难有效利用字符串长度相同这个条件。