题目大意:
序列 S **[s1……sn]**由n个字符’('或’)‘组成,且这两个字符的数目相等可以进行将区间[l,r]里的内容翻转。规定,如果一个串是干净的,那么他的满足括号匹配原则。给出K,通过翻转的操作,使得其所有的前缀子串中只有K个是干净的。翻转的操作不超过n次,且不需要翻转次数最小。
输入:
样例数T,每组样例先输入n,k,再输入s;
输出:
m次操作,每次操作的区间。
思路:既然不要求最优化修改,可以直接采用暴力且小于n次的求法,直接写出翻转到最后的序列 ()()(……),意思是前面直接有k-1个(),最后一个用()括起来剩下的,这样还是只有k个前缀满足条件的。
#include<bits/stdc++.h>
using namespace std;
int t,n,k;
string a;
pair<int,int>ans[2001];
void rever(int l,int r){
for(int i=0;i<(r-l+1)/2;i++){
swap(a[l+i],a[r-i]);
}
}
int main()
{
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&k);
cin>>a;
int cnt=0,l,r;
char tmp;
string res;
for(int i=1;i<k;i++) res+="()";
for(int i=1;i<=n/2-k+1;i++) res+="(";
for(int i=1;i<=n/2-k+1;i++) res+=")";
for(int i=0;i<n;i++){
int j=i;
while(a[j]!=res[i]){
j++;
}
ans[++cnt].first=i+1;
ans[cnt].second=j+1;
rever(i,j);
}
printf("%d\n",cnt);
for(int i=1;i<=cnt;i++){
printf("%d %d\n",ans[i].first,ans[i].second);
}
}
}
膜拜大神代码:思路相同
科普一个C库函数:strrchr 在参数 str 所指向的字符串中搜索最后一次出现字符 c(一个无符号字符)的位置。
声明char *strrchr(const char *str, int c)
#include<bits/stdc++.h>
char a[20000], ar[] = "()";
void rev(int l, int r){
r = std::max(l,r);
printf("%d %d\n", l+1, r+1);
for(int i=0;i<=(l+r)/2-l;i++) std::swap(a[l+i], a[r-i]);
}
int main(){
int i, n, k, qq;
scanf("%d",&qq);
while(qq--){
scanf("%d%d%s", &n,&k, a);
printf("%d\n", n);
for(i=0;i<n;i++) rev(i, strrchr(a, ar[(i/2 <=k-2) && (i%2)])-a);//找到'('或者')'在a最后一次出现位置。
}
return 0;
}