当前位置: 代码迷 >> 综合 >> 【cf】D. Repetitions Decoding
  详细解决方案

【cf】D. Repetitions Decoding

热度:97   发布时间:2023-12-06 13:14:28.0

题意:

给出一个长度为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 secondvoid 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);//两个相同的数消掉了,要加2mdf+=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;
}