题意:将一个长度为n的字符串改成一个回文,但是修改是有代价的,开始有一个p,表示p指向的字符的位置,每次修改只能修改p所指向的字符,修改的代价为a->b为1,c->a为2,a-z为1,y->a为2,以此类推,并且p可以左右移动,每移动一个位置代价为1,求最少的代价使字符串变成回文
思路:因为字符之间相互转化的代价是一样的,如 a-g 与g-a的代价是一样的,所以,以n-1>>1 位置的一个或者2个字符作为中点,只需要改变某一边就可以了,和和改变另一边的代价是等价的,如果p的初始位置不在改变的一遍,则只需将p的位置换到另一边对应的位置就可以了,每次需要记录p所需要到的最左边和最右边的位置lm和rm,用于计算改变p的位置所花的代价,最后计算p所花代价的时候需要注意分类讨论,将lm和rm与p的位置关系作为分类讨论的点
AC代码:
#include "iostream" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "set" #include "map" #include "algorithm" #include "stdio.h" #include "math.h" #define ll long long #define bug(x) cout<<x<<" "<<"UUUUU"<<endl; #define mem(a) memset(a,0,sizeof(a)) #define mp(x,y) make_pair(x,y) using namespace std; const long long INF = 1e18+1LL; const int inf = 1e9+1e8; const int N=1e5+100; ///2015 HIAST Collegiate Programming Contest char a[N]; int n,p; int change_cost(int i){ char ch=a[i]; int k1=0, k2=0; for(int j=1; j<=60; ++j){ k1=j; ch++; if(ch>'z') ch='a'; if(ch==a[n-i+1]) break; } ch=a[i]; for(int j=1; j<=60; ++j){ k2=j; ch--; if(ch<'a') ch='z'; if(ch==a[n-i+1]) break; } return min(k1,k2); } int main(){ int t; cin>>t; while(t--){ cin>>n>>p>>a+1; int mid=n+1>>1; int lm=inf,rm=-inf; ll ans=0; for(int i=1; i<=mid; ++i){ if(a[i]!=a[n-i+1]){ lm=min(lm,i); rm=max(rm,i); ans+=change_cost(i); } }//cout<<lm<<" "<<rm<<endl; if(lm>rm){ cout<<0<<endl; continue; } if(p>mid) p=n-p+1; if(rm<=p && lm<=p){ ans+=abs(p-lm); } else if(rm>p && lm>p){ ans+=abs(p-rm); } else{ int step_l=abs(p-lm), step_r=abs(p-rm); ans+=2*min(step_l,step_r)+max(step_l,step_r); } cout<<ans<<endl; } return 0; }