SPOJ 4103 Extend to Palindrome(EPALIN)

[成绩]
ID
DATEPROBLEMRESULTTIMEMEMLANG
34049822010-03-23 03:04:35Extend to Palindromeaccepted0.182.7M

C++

4.3.2

34049692010-03-23 02:49:04Extend to Palindromewrong answer0.162.7M

C++

4.3.2

34049512010-03-23 02:32:24Extend to Palindrometime limit exceeded-2.9M

C++

4.0.0-8

34049382010-03-23 02:25:08Extend to Palindrometime limit exceeded-3.0M

C++

4.0.0-8

34048872010-03-23 01:53:47Extend to Palindromeruntime error (SIGSEGV)0.002.8M

C++

4.3.2

34048722010-03-23 01:47:46Extend to Palindromeruntime error (SIGSEGV)0.002.8M

C++

4.3.2

34048692010-03-23 01:46:36Extend to Palindromeruntime error (SIGSEGV)0.002.8M

C++

4.3.2

34048582010-03-23 01:44:06Extend to Palindromeruntime error (SIGSEGV)0.002.8M

C++

4.3.2

34048402010-03-23 01:33:55Extend to Palindromeruntime error (SIGSEGV)0.0012M

C++

4.3.2

34048392010-03-23 01:32:54Extend to Palindromeruntime error (SIGSEGV)0.002.8M

C++

4.3.2

34047972010-03-23 01:20:20Extend to Palindromecompilation error--

C++

4.3.2

[成绩说明]
    刚开始做的CE,就是……WINDOWS与LINUX的区别,然后就很悲剧的CE了……
    然后一串RE,就是……用了链表,不知道为什么就RE了——由此得出结论:链表能不用就不用……
    接着两个TLE,那是误把<string>库里的str=x+str当成O(1)的,程序是O(KN^2)——而我一直认为这个算法是O(KN)的
    然后就是一个WA,本来一直想不通为什么,经过TonyβΛ程序的对拍,得出特殊数据pqqpq - pqqpqqp,而我的程序结果是pqqpqpqqp。
    最后就很悲剧的AC了……
    整道题共花费时间2小时
[解题报告](感谢评论给我的一组数据使我的算法WA了)
    首先,解释下题目,就是告诉你一个串,求以这个串为前缀的最短回文串。
    尹神牛说可以用拓展KMP,不过我没学过拓展KMP,就不说他了。
    接下来就是正式的算法:用两个指针,分别指向头和尾,如果头尾指向的字母相同,就分别向里面推进一格,否则尾指针一直向后推,直到尾指针指向的字母与头指针指向的字母相同,然后从这里继续向里推进一格;若没有,那么尾指针指向末尾,头指针向里推进。
    这样,当头尾指针交叉时,头尾指针中间就是最后要求的回文串的中心,然后……不需要教了吧……
    为什么这个算法是对的呢?
    好,我们来证明它!
    ①若输入串是回文串[ abba - abba ]:显然头尾指针一直向里面推进,直到相交:显然最后到得要求的回文串的中心与原串的回文中心重合。所以此种情况下,该算法是正确的。
    ②若输入串是无重复字符的串(就是串中任意两个字符都不同)[ xyz - xyzyx ]:那么尾指针一直指向末尾(因为无论头指针指向哪个字符,尾指针指向的字符都不会与它相同),头指针不断推进,直到与尾指针重合。这时该算法求出的答案的回文中心是原串的末尾。所以此种情况下,该算法是正确的。
    ③若输入串只有一个回文中心(所有相同字符的中心聚集在一个点上),且该串不是回文串[ hzsyxxy - hzsyxxyszh ]:首先,刚开始尾指针指向输入串末尾,头指针不断推进,一直到头尾指针指向的字符相同后,头尾指针一起向内推进,最后答案的回文中心与输入串的回文中心重合。所以此种情况下,该算法是正确的。
    ④若输入串有多个回文中心[ pqqpq - pqqpqqp ,amanaplanacanal - amanaplanacanalpanama ,abbaba - abbababba]:显然,我们应该确定下最后的回文中心的位置。按照一种显然的贪心策略,显然选择的回文中心越向前越好——但这个贪心策略是错误的,因为我们必须先保证输入串是答案串的一个前缀。那么我们稍微修改一下策略:按照一定的规则,选择的回文中心越向前越好。那这个规则是什么呢?显然,假如输入串是答案串的前缀,那么回文中心应该是与最后一个字符相同的字符的回文中心(为什么呢?我也不知道,反正就是对的)。在这个前提下,该贪心策略就是正确的了(呃……我还是不能证明这个命题,反正从直觉上看是正确的)。然后来分析算法的答案的回文中心:首先和③一样,尾指针不动,头指针向内推进,直到头尾指针相同。假如头尾指针中间这段是回文串,那它的回文中心显然就是中间这段回文串的回文中心,而且这个回文中心必然是满足前提的贪心出的回文中心(如第2个样例)。假如头尾之间的这段不是回文串,那么随着头指针的推进,当它指向的与尾指针不相同的时候,尾指针会后移。接下来一个非常重要的命题是:为什么尾指针后移不影响答案。
    首先,忽略刚开始那段。那么得到一个头尾相同的串。当尾指针要后退时,头尾两段应该是相同的。当尾指针退到一个符合要求的地方时,尾指针后面的那一段必定是头指针前面那一段的后缀(这句话显然有问题,当初由于太过自信了)。所以,这样做只是将回文中心向后移(这个证明非常不充要……姑且认为这个证明是正确的伪证明。为什么这个证明是正确的伪证明呢?因为我AC了,就这么简单)。
    所以此种情况下,该算法是正确的。
    综上所述,该算法是正确的(貌似形似神似情况不止这么几种,不过似乎其他情况可以归约到这4种情况上。对么?我也不知道)

    最后,由于我的伪证明的错误,所以应该在每寻找到一个回文中心后,检查下输入是否为答案串的前缀,这样更可以保证答案的正确性。
[程序]  // 这个程序真的非常短,比我刚开始预计的要短很多……
// TASK: spoj_EPALIN
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;
char str[100010];
int main(int argc, char *argv[])
{
    while (gets(str))
    {
          long n;
          if ((n=strlen(str))<=0) continue;
          long b=0,e=n-1;
          while (b<e)
          {
                while (e<n&&str[b]!=str[e]) e++;
                if (e>=n) b++,e=n-1;
                else b++,e--;
    if (e<=b)
    {
     long i=b,j=e;
     while (j<n&&str[i]==str[j]) i--,j++;
     if (j<n) e++;
    }
          }
          for (long i=0;i<=b;i++)
              printf("%c",str[i]);
          for (long i=e-1;i>=0;i--)
              printf("%c",str[i]);
          printf("\n");
    }
    return EXIT_SUCCESS;
}
//pqqpq - pqqpqqp
//abbaba - abbababba


转载于:https://www.cnblogs.com/klarkxy/archive/2010/03/23/10017172.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值