2017 多校赛6 Kirinriki hdu 6103

来源:互联网 发布:matlab模块化编程 编辑:程序博客网 时间:2024/06/06 12:45

飞机直达

题目

题目意思:题意还是不难的吧,虽然我一开始没看懂non-overlapping是不覆盖的意思。。。还是说一下吧, 给定一个串S, 要找两个最长的不相互覆盖且长度相等的子串s1,s2,使得把其中一个子串倒转后与另一子串的距离不大于m(感觉有点类似回文串的东西)。。
思路:一开始我没注意道两个串不可相互覆盖, 想了一个dp,状态转移很奇怪。 后来发现看错题目却来了思路Orz。。。子串长度相等,不可相互覆盖,那么他们一定是 “对称” 的,这个对称是指在忽略一定距离误差后轴对称。那么枚举中心就是一个很自然的思路了。那么当中心确定之后,要怎么求最长的子串呢?让我们只考虑中心右边的子串s2,我们知道左边字符可以通过右边字符下标和中间位置直接求得(即s2的dis可得), 这样问题就转化成了:求一个最长子串s2,dis不大于m,这里dis已经可以看成是s2每个字符的cost了。说到这里,思路差不多就出来了吧。。。是的,尺取法!!!
赛后想了一下,似乎串可以相互覆盖也可以用相同的思路来做-_-.

#include <cstring>#include <cstdio>#include <iostream>using namespace std;typedef long long LL;#define MAXN 6int const maxn=5100;char str[maxn];int m;inline int dis(char a, char b){    return a>b? a-b : b-a;}int main(void){    int T;    for (scanf("%d", &T); T; T--){        scanf("%d", &m);        scanf("%s", str+1);        int ans=0, len=strlen(str+1);        for (int mi=1; mi<=len; mi++){//枚举中点,mi作为中点。s1,s2都不取str[mi]            int s=mi+1, t=mi+1, sum=0;            for (;;){                while (t<=len && mi*2-t>0 && sum<=m){                    sum+=dis(str[t], str[mi*2-t]); t++;                    if(sum<=m) ans= max(ans, t-s);//这个可省不得,挑战的模板应该是有问题                }                if(sum<=m) ans= max(ans, t-s);                if (t>len || mi*2-t<=0) break;                sum-=dis(str[s], str[mi*2-s]);                s++;            }        }        for (int mi=1; mi<=len; mi++){//枚举中点,mi与mi+1的中间的空位作为中心轴。mi作为s2的第一个字符下标,不属于s1.            int s=mi, t=mi, sum=0;            for (;;){                while (t<=len && mi*2-t-1>0 && sum<=m){                    sum+=dis(str[t], str[mi*2-t-1]); t++;                    if(sum<=m) ans= max(ans, t-s);//同样不能省                }                if(sum<=m) ans= max(ans, t-s);                if (t>len || mi*2-t-1<=0) break;                sum-=dis(str[s], str[mi*2-s-1]);                s++;            }        }        printf("%d\n", ans);    }    return 0;}

这道题是个想法+编程技巧题,感觉算是与水题拉开的第一个有区分度的题吧

原创粉丝点击