题意:给出string长度n<=1e5(cyclic) 和一个游标p,问最小花费多少次操作能把string变成回文 .(4个操作:左右移动游标p,增大或者减小游标所指的值)
若s[i]!=s[n-i+1] 则要修改其中一个的值,最多修改n/2次,每次花费值时固定的 则只有求出最少的移动距离即可.
贪心: "1 ..p .. n/2....n" 可以看出p~n,和p~n/2~1的移动距离时一样的,则p可以只在1~n/2范围内移动,求出要修改的范围mn~mx确定移动顺序即可
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+20;
char s[N];
int n,p,w[30][30];
int main()
{
//w[i][j] the minnum cost of changing char i to char j
for(int i=1;i<=26;i++)
{
for(int j=i;j<=26;j++)
{
w[i][j]=w[j][i]=min(j-i,i+26-j);
}
}
while(cin>>n>>p)
{
scanf("%s",s+1);
int res=0,mx=0,mn=1e6;
//在n/2~n做修改等价于在 1~n/2做修改.
if(p>n/2)
{
p=n-p+1;
}
for(int i=1;i<=n/2;i++)
{
//修改s[i]的代价
if(s[i]!=s[n-i+1])
{
res+=w[s[i]-'a'+1][s[n-i+1]-'a'+1];
mx=max(mx,i);
mn=min(mn,i);
}
}
if(res==0)
{
cout<<0<<endl;
continue;
}
//修改范围为mn~mx
//p的移动范围最大为1~n/2,根据mn,mx,p确定移动顺序即可
if(p<=mn)
res+=(mx-p);
else if(p>mn&&p<mx)
{
int a=min(p-mn,mx-p);
int b=max(p-mn,mx-p);
res+=2*a+b;
}
else
res+=(p-mn);
cout<<res<<endl;
}
return 0;
}