CF ECR92 C. Good String

题目链接
题目概述
题目中定义了字符串(a_1a_2dots a_n)的左旋转(a_2a_3dots a_na_1)和右旋转(a_na_1a_2dots a_{n-1}),然后定义了一个Good String的东西,左旋转和右旋转是同一个字符串,即(a_2a_3dots a_na_1=a_na_1a_2dots a_{n-1}),现在给定一个字符串,计算这个字符串经过删减后可以得到一个Good String需要删减的最小的字符的数量.输入的输入格式为,先输入一个整数T,表示测试的数量,然后输入T个连续的仅由0~9构成的字符串s.输出需要删减的最小的字符串的数量.输入数据的规模:
思路
根据上面那个Good String的定义,可以得到对于一个Good String(b_1b_2cdots b_k),只可能存在以下两种情况:
- (b_1=b_2=cdots=b_k)
- (b_1=b_3=cdots=b_{k-1},b_2=b_3=b_4cdots=b_k, b_1 != b_2,k\%2=0)
从上面的定义代换可以得到,这里简单说一说为什么(k\%2=0)时奇偶位上的数字都相同才是Good String,对于一个Good String(xyxycdots xy)来说,左旋转之后得到的是(yxycdots xyx),有旋转之后得到是(yxyxycdots x)旋转实际上是把原来奇偶位上的数字进行了一个简单的变换,原来奇数位的数字变成偶数位的,偶数位的变成奇数位的.如果不满足(k%2=0)的话,(xyxycdots xyx),左旋转之后是(yxycdots xyxx),二右旋转则是(xxyxycdots xy),这样的两个字符串就不相等了.
所以可以先从(a_1a_2cdots a_n)中计算满足上面任意一个Good String条件可以得到的最长Good String的长度,然后用字符串总长减去这个最长的Good String的长度得到的就是需要删除的最少的字符的数量.
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+5;
const int M = 10;
int buf[N];
int count_one(size_t n, int v){
int ans = 0;
for(auto i = 0; i < n; ++i){
if(buf[i] == v){
++ans;
}
}
return ans;
}
int count_two(size_t n, int x, int y){
int ans = 0;
for(auto i = 0; i < n; ++i){
if( ans & 1){
// 上一个x后面出现的y
if(buf[i] == y){
++ans;
}
}else{
// 最初的x或者上一个y后面的x
if(buf[i] == x){
++ans;
}
}
}
// 最后得到的ans是xyxy...(xy)的个数,可能存在末尾是单独一个x的情况
if( ans & 1)
--ans;
return ans;
}
void solve(size_t n){
int ans = 0;
// 计算xxx出现的次数
for(int i = 0; i < M; ++i){
ans = max(ans, count_one(n, i));
}
// 计算xyxy...出现的次数,两者取最大值
for(int i = 0; i < M; ++i){
for(int j = 0; j < M; ++j){
if( i != j){
ans = max(ans, count_two(n,i,j));
}
}
}
// 最后的ans就是所谓的good string的最大长度,n-ans就是应该去掉的部分的长度
cout<<(n-ans)<<endl;
}
int main(int argc, const char** argv) {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int t;
cin>>t;
while(t--){
string s;
cin>>s;
for(auto i = 0; i < s.size(); i++){
buf[i] = s[i]-'0';
}
solve(s.size());
}
return 0;
}
通过count_one计算从字符串可以提取出(xxxcdots x)这种Good string的长度,然后取其中长度的最大值;通过count_two计算出从字符串中提取出(xyxycdots xy)这种Good String的字符串的长度,在扫描原来字符串是,用ans记录这个拟Good String的长度(如果最后的ans是奇数要减一,对应末尾多一个x的情况,末尾不会多余y,因为y一定是和x配对的.在第二种情况下,要关注前面一个字符的类型,比如如果前面统计的是x,那么只有遇到y才会扩大Good String的长度,同时更改关注的字符为y,这样当下一轮遇到x时才统计扩大Good string的长度,这里面是通过ans的奇偶性来实现的,当ans是偶数时表示期待下一个字符是x,当ans是奇数时表示期待下一个字符是y.扫描完毕后,有可能找到的拟Good String末尾多余一个x,此时需要丢弃这个x得到的才是Good String.枚举所有的数字字符可能的组合类型(两个数字字符此时不能相同),从中计算得到的Good String的最大值,和上面第一种情况的最大值再去最大值,得到的就是可以得到的最长的Good String的长度.用字符串总长度减去这个长度得到的就是要删减的字符的数量.