题意:
给出一个长度为n的序列,要求你把这个序列构造成几个两两相连的重复连续的子序列,比如123123就满足题意,123123123不满足题意,可以进行的操作有在某个数后面插入两个相同的数,这个数是任意的。
思路:
对于任意一串数,都可以构造出这一串数加这一串数倒过来的数,比如123456,对于123,可以在3后面插入一个1,变成123 11 456,然后在1后面插入2,变成123 1221 456,然后在2后面插入3,变成123 123 321 456,对于任意一串数都可以这么构造。官方给的n方的题解,是在原来的序列中找到相同的两个数字,把这两个数字放在一起,然后构成一组序列,然后这两个数字中间的数留下来,这样一直两两抵消,直到结束,比如ABCACB,会先找到两个A,变成ABC ABC CBA ACB, 然后变成CBAA CBAA AA BCCB,这样就把A消掉了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define PII pair<int, int>
#define x first
#define y second
void move(vector<int> &a, vector<PII> &ans, vector<int> &lens, int &mdf, int l, int r)
{
for(int i=l; i<=r; i++) ans.push_back({r+1+mdf+i-2*l, a[i]});
if(r-l+1>0) lens.push_back((r-l+1)*2);
mdf+=(r-l+1)*2;
reverse(a.begin()+l, a.begin()+r+1);
}
void reverse_last_to_front(vector<int> &a, vector<PII> &ans, vector<int> &lens, int &mdf, int l, int r)
{
move(a, ans, lens, mdf, l, r-1);
move(a, ans, lens, mdf, l, r);
}
int main(){
int t;
scanf("%d", &t);
while(t--)
{
int n;
scanf("%d", &n);
vector<int> a(n);
for(int i=0; i<n; i++) scanf("%d", &a[i]);
if(n%2)
{
puts("-1");//如果有一个数的出现次数为奇数,那就无法构造出来
continue;
}
bool flag=0;
unordered_map<int, int> mp;
for(int i=0; i<n; i++) mp[a[i]]++;
for(auto &it: mp)
{
if(it.y%2)//如果有一个数的出现次数为奇数,那就无法构造出来
{
puts("-1");
flag=1;
break;
}
}
if(flag) continue;
vector<PII> ans;
vector<int> lens;
ans.reserve(n*n*2);
lens.reserve(n*2);
int mdf=0;//已经满足要求的序列长度
for(int i=0; i<n; i+=2)
{
int fnd=(int)(find(a.begin()+i+1, a.end(), a[i])-a.begin());
reverse_last_to_front(a, ans, lens, mdf, i, fnd);
lens.push_back(2);//两个相同的数消掉了,要加2
mdf+=2;//两个相同的数消掉了,要加2
}
cout<<(int)ans.size()<<endl;
for(auto &it: ans)
{
cout<<it.x<<" "<<it.y<<endl;
}
cout<<(int)lens.size()<<endl;
for(auto &it: lens)
{
cout<<it<<" ";
}
cout<<endl;
}
return 0;
}