场上只做出3题,赛后看jiangly老师的代码过了D
真实的惊叹于jiangly老师思路的巧妙 & 代码的优美 %%%
jiangly老师视频链接
题目链接
https://codeforces.com/contest/1642/problem/D
做法
就不说错误的思路了,总之就是找不到问题关键所在,写了假算法
如果在数组中间插入数会对之后的数下标产生影响,因此插入操作考虑从后往前做。
从现有的数组的最末尾开始(position:i),找到前一个和它一样的数(position:j),往j之后插入i与j中间的数
这里的插入不是真的往数组里面插入数,是加进答案;
真实发生的事情是去掉i和j处的数,然后把它们中间部分的数翻转(结合本题题意理解)
这样可以大大简化代码的写法
细节见代码
放一下我参考jiangly老师的代码写的代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,t,x,q,d;
map<int,int>mp;
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
vector<int>a;
for(int i=1,x;i<=n;i++){
scanf("%d",&x);
a.push_back(x);
}
vector<pair<int,int>>ans;
vector<int>len;
bool f=1;
while(!a.empty()){
int i=a.size()-1;
int j=i-1;
while(j>=0&&a[i]!=a[j]){
j--;
}
if(j==-1){
f=0;
puts("-1");
break;
}
for(int k=0;k<i-j-1;k++){
ans.push_back(make_pair(j+k,a[i-1-k]));
}
len.push_back(2*(i-j));
reverse(a.begin()+j+1,a.begin()+i);
a.pop_back();
a.erase(a.begin()+j);
}
if(!f) continue;
printf("%d\n",ans.size());
for(int i=0;i<ans.size();i++){
printf("%d %d\n",ans[i].first,ans[i].second);
}
reverse(len.begin(),len.end());
printf("%d\n",len.size());
for(int i=0;i<len.size();i++){
printf("%d ",len[i]);
}
puts("");
}
return 0;
}