Codeforces Round #773 (Div. 2) D. Repetitions Decoding 构造

https://codeforces.com/contest/1642/problem/D

  • 给你一个数列,让你从这个数列构造出一个新数列,使得这个新数列能够完全划分成若干组连续序列,满足 A   t a n d e m   r e p e a t A\ tandem\ repeat A tandem repeat,也就是对于 i ∈ [ 1 , k ] i\in [1,k] i[1,k],有 s i = s i + k s_i=s_{i+k} si=si+k
  • 思路其实很简单,这个当时赛场上想出来了,无解的判断比较显然,如果有一个数出现次数为奇数则一定无解;考虑有解的情况,比如说序列为 1 , 2 , 3 , 4 , 1 1,2,3,4,1 1,2,3,4,1,现在只考虑怎么构造出这种 t a n d e m   r e p e a t tandem\ repeat tandem repeat,我们在最后一个 1 1 1后面加上两个 2 2 2,变成 1 , 2 , 3 , 4 , 1 , 2 , 2 1,2,3,4,1,2,2 1,2,3,4,1,2,2,同理在 2 2 2后面插入 3 3 3,得到 1 , 2 , 3 , 4 , 1 , 2 , 3 , 3 , 2 1,2,3,4,1,2,3,3,2 1,2,3,4,1,2,3,3,2,在 3 3 3后面插入 4 4 4,得到 1 , 2 , 3 , 4 , 1 , 2 , 3 , 4 , 4 , 3 , 2 1,2,3,4,1,2,3,4,4,3,2 1,2,3,4,1,2,3,4,4,3,2,这样 [ 1 , 2 , 3 , 4 , 1 , 2 , 3 , 4 ] , 4 , 3 , 2 [1,2,3,4,1,2,3,4],4,3,2 [1,2,3,4,1,2,3,4],4,3,2方框部分就是构造出来的序列,然后接下来继续构造即可
  • 当时想的是怎么实现呢?要是直接模拟的话可能也行,但是有个好的思路是每一组插入的最后结果实际上是 i , j i,j i,j之间的所有数正着一遍再反着一遍拼接到 j j j的后面;实际上这里面 n n n只有 500 500 500,而且预计不会有太多次的插入,完全可以暴力,所以只需要一直 i n s e r t insert insert就好了,注意计算清楚当前的位置
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

int main(){
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  int t;
  cin >> t;
  while(t--){
    int n;
    cin >> n;
    vector<int> a;
    map<int, int> mp;
    for(int i=1;i<=n;i++){
      int x;
      cin >> x;
      a.push_back(x);
      mp[x] += 1;
    }
    bool ok = true;
    for(auto i : mp){
      if(i.second & 1) ok = false;
    }
    vector<int> len;
    if(ok){
      vector<pair<int, int> > ans;
      for(int i=0;i<a.size();){
        int j = i + 1;
        vector<int> v;
        while(a[i] != a[j]){
          v.push_back(a[j]);
          j += 1;
        }
        for(int k=i+1;k<j;k++){
          ans.push_back(make_pair(k - i + j, a[k]));
          // cout << k - i + j << ' ' << a[k] << '\n';
        }
        a.insert(a.begin() + j + 1, v.begin(), v.end());
        reverse(v.begin(), v.end());
        a.insert(a.begin() + j + 1 + (int)v.size(), v.begin(), v.end());
        len.push_back((j - i) * 2);
        i = 2 * j - i;
      }
      cout << ans.size() << '\n';
      for(auto i : ans){
        cout << i.first << ' ' << i.second << '\n';
      }
      cout << len.size() << '\n';
      for(int i=0;i<(int)len.size();i++){
        cout << len[i] << " \n"[i == (int)len.size() - 1];
      }
    }else{
      cout << -1 << '\n';
    }
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Clarence Liu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值