题目:戳我
题意:给定长度为n的字符串,给定初始光标位置p,支持4种操作,left,right移动光标指向,up,down,改变当前光标指向的字符,输出最少的操作使得字符串为回文。
分析:只关注字符串n/2长度,up,down操作是固定不变的,也就是不能优化了,剩下就是left,down的操作数,细想下中间不用管,只关注从左到中间第一个要改变的位置和最后一个要改变的位置即可,具体看代码。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int M = 1e5+5;int n, p; char str[M]; int main() {while( ~scanf("%d %d", &n, &p ) ) {getchar();gets( str+1 );int sumchg = 0; //up,down的操作总数int first = 0; //第一个要改变的位置bool firstjd = true;int last = 0; //最后一个要改变的位置for( int i=1; i<=n/2; i++ ) {int d = abs( str[i]-str[n+1-i] );if( d ) {if( firstjd ) {first = i;firstjd = false;}last = i;sumchg += min( d, 26-d ); //选择up或者down的最小操作数 }}if( p > n/2 ) //由于回文左右对称,所以p在中间右边时也可将p当左边对称位置计算p = n+1-p;int ret = 0;if( sumchg == 0 ) { //不需要改变输出0printf("%d\n", ret);continue;}if( first >= p ) //如果p在第一个要改变的左边,p只能向右走,即执行right操作ret += sumchg + last - p; else if( last <= p ) //如果p在最后一个要改变的右边,p只能向左走,即执行left操作ret += sumchg + p - first;elseret += min( 2*(p-first)+last-p, 2*(last-p)+p-first ) + sumchg; //p在中间,取求向左向右走的最小值printf("%d\n", ret);}return 0; }