题解:P15072 [ICPC 2024 Chengdu R] Arrow a Row
P15072 [ICPC 2024 Chengdu R] Arrow a Row 题解
题意
题目要求我们通过若干次绘制操作,将一个全 * 的初始字符串转换成目标字符串
- 字符串以
>开头,以>>>结尾。 - 字符串的其余部分仅由
-组成。
我们需要判断是否能在不超过
思路
通过分析发现,最终字符串 > 必须位于某次操作的起点或最后三个位置,因为操作的中间部分只能是 -。因此我们可以采用贪心策略从后往前构造操作。
-
初步检查。
-
从后往前处理:
- 首先处理末尾的
>>>部分,尽可能多地构造从位置1 开始的覆盖操作。 - 然后处理中间剩余部分,为每个
>构造单独的操作。
- 首先处理末尾的
-
验证可行性,确保中间部分至少有一个
>。
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int T;
cin>>T;
while(T--){
string s;
cin>>s;
int n=s.size();
s=' '+s; // 添加前导空格,使下标从1开始
// 初步检查:长度、首尾字符
if(s[n]!='>'||s[n-1]!='>'||s[n-2]!='>'||s[1]!='>'||n<5){
cout<<"No\n";
continue;
}
int r=n+1; // 记录当前未覆盖区域的右边界
vector<pair<int,int> > v;// 存储操作序列
// 第一步:处理末尾的>>>部分
// 从后往前,每遇到连续的>>>就构造一个从位置1开始的覆盖操作
for(int j=n;j>=5;j--){
if(s[j-2]=='>'){// 检查j-2,j-1,j是否构成>>>
r--;// 缩小未覆盖区域
v.push_back({1,j});// 添加从1到j的操作
}
else break;// 不再连续,停止
}
// 第二步:处理中间剩余部分
bool f=0;// 标记是否找到有效的'-'
for(int i=2;i<=r-3;i++){// 遍历未覆盖区域
if(s[i]=='-')f=1;// 找到至少一个'-'
// 对于每个'>',构造一个操作覆盖到当前边界r
if(s[i]=='>'&&i!=r-3){// 避免在边界处重复操作
v.push_back({i,r-i+1});// 添加从i开始,长度为r-i+1的操作
}
}
// 验证:必须至少有一个'-'才是有效构造
if(f==0)cout<<"No\n";
else{
cout<<"Yes "<<v.size()<<"\n"; // 输出操作数量
for(auto o:v)cout<<o.first<<" "<<o.second<<"\n";// 输出每个操作
}
}
return 0;
}