更好的阅读体验
思路
观察题目可以发现 A 操作最多只能执行 \(n\) 次,超过以后字符串又会回到初始状态。
首先考虑 A 操作如何实现,一种办法是将 \(S\) 在原串后复制一遍,通过移动一个记录初始位置的指针(本文中为 \(i\))来实现截取 \(n\) 位字符。每次移动指针代价都为 \(A\)。
接下来考虑 B 操作的代价计算。我们可以判断之前截取的字符串是否为回文。回文字符串判断应该都会吧通过移动起始位置和结束位置指针,比较两指针对应的字符是否相同进行回文判断,每次遇到不同,总代价都加 \(B\)。
值得注意的是结束位置指针的取值。每次 A 操作执行完成,截取出的字符串末位下标为 \(n+i-1\),在此基础上再减去起始位置即可。
回文判断部分代码:
/*i 为 A 操作中起始位置指针,t 为总代价*/
for(int j=0;j<n/2;j++)//回文判断循环变量只需到 n/2
{
int x=i+j;//起始位置
int y=n+i-1-j;//结束位置
if(s[x]!=s[y])
{
t+=b;
}
}
以 A 操作中起始位置指针作为外层循环变量,范围 \(0\sim n-1\),内层循环为回文串判断。总时间复杂度 \(O(n^2)\)。
一些小细节
-
观察数据范围可知需使用 \(\text{long long}\);
-
最大值可取值 \(2^{62}\) 即
1ll<<62
。
完整代码
#include<cstdio>
#include<string>
#include<iostream>
#define INF 1ll<<62
#define ll long long
#define int ll
using namespace std;
int n,a,b;
int ans=INF;
string s;
signed main()
{
scanf("%lld%lld%lld",&n,&a,&b);
cin>>s;
s+=s;
for(int i=0;i<n;i++)
{
int t=a*i;
for(int j=0;j<n/2;j++)
{
int x=i+j;
int y=n+i-1-j;
if(s[x]!=s[y])
{
t+=b;
}
}
ans=min(ans,t);
}
printf("%lld\n",ans);
return 0;
}
标签:Rotate,题解,位置,ABC286C,include,字符串,指针,回文
From: https://www.cnblogs.com/makerlife/p/solution-ABC286C.html