Codeforces Round #773 (Div. 2) D

16 篇文章 0 订阅

题目大意:

  • 长度为n的序列a,通过输出一定的操作序列使得最终的a可以由重复序列组成,再输出每个重复序列的长度。如果不存在这样的操作序列,则输出-1.

    • 重复序列定义:长度为2k的序列,且满足 x i = x i + k x_i=x_{i+k} xi=xi+k
    • 操作方式:选择一个位置插入一对相同的数(自定义)
  • 数据范围:

    1 ≤ t ≤ 30000 1\le t\le 30000 1t30000

    n ≤ 500 n\le 500 n500

    a i ≤ 1 e 9 a_i\le1e9 ai1e9

    保证 ∑ n 2 ≤ 250000 \sum n^2 \le 250 000 n2250000

  • 例子:
    1 , 3 , 1 , 2 , 2 , 3 在 位 置 1 插 入 一 对 3 : 1 , 3 , 3 , 3 , 1 , 2 , 2 , 3 在 位 置 5 插 入 一 对 3 : 1 , 3 , 3 , 3 , 1 , 3 , 3 , 2 , 2 , 3 在 位 置 5 插 入 一 对 3 : 1 , 3 , 3 , 3 , 1 , 3 , 3 , 3 , 3 , 2 , 2 , 3 在 位 置 10 插 入 一 对 3 : 1 , 3 , 3 , 3 , 1 , 3 , 3 , 3 , 3 , 2 , 3 , 3 , 2 , 3 ( [ 1 , 3 , 3 , 3 ] + [ 1 , 3 , 3 , 3 ] ) + ( [ 3 , 2 , 3 ] + [ 3 , 2 , 3 ] ) 1,3,1,2,2,3 \\ 在位置1插入一对3:1,3,3,3,1,2,2,3 \\ 在位置5插入一对3:1,3,3,3,1,3,3,2,2,3 \\ 在位置5插入一对3:1,3,3,3,1,3,3,3,3,2,2,3 \\ 在位置10插入一对3:1,3,3,3,1,3,3,3,3,2,3,3,2,3 \\ ([1,3,3,3]+[1,3,3,3])+([3,2,3]+[3,2,3]) 1,3,1,2,2,313:1,3,3,3,1,2,2,353:1,3,3,3,1,3,3,2,2,353:1,3,3,3,1,3,3,3,3,2,2,3103:1,3,3,3,1,3,3,3,3,2,3,3,2,3([1,3,3,3]+[1,3,3,3])+([3,2,3]+[3,2,3])

解题思路:

  • 首先每个数都必须出现偶数次才有可能找得到答案

    假设x出现了奇数次

    • 若插入过程始终没x,则有一个x始终不能匹配
    • 若插入过程有x,因为每次插入都是偶数个x,所以仍然会有一个x不能匹配
  • 通过插入的方式可以将某一段变为"倒序":

    例如:
    . . . , x , y , z , . . . . . . , x , y , z , x , x , . . . . . . , x , y , z , x , y , y , x , . . . . . . , x , y , z , x , y , z , z , y , x , . . . 最 终 序 列 变 成 了 : [ . . . ] + [ ( x , y , z ) + ( x , y , z ) ] ) + [ z , y , x ] , . . . 因 为 [ ( x , y , z ) + ( x , y , z ) ] ) 可 以 不 用 理 了 , 所 以 相 当 于 把 [ x , y , z ] 倒 序 了 ...,x,y,z,... \\ ...,x,y,z,x,x,... \\ ...,x,y,z,x,y,y,x,... \\ ...,x,y,z,x,y,z,z,y,x,... \\ 最终序列变成了:[...]+[(x,y,z)+(x,y,z)])+[z,y,x],... \\ 因为[(x,y,z)+(x,y,z)])可以不用理了,所以相当于把[x,y,z]倒序了 ...,x,y,z,......,x,y,z,x,x,......,x,y,z,x,y,y,x,......,x,y,z,x,y,z,z,y,x,...[...]+[(x,y,z)+(x,y,z)])+[z,y,x],...[(x,y,z)+(x,y,z)])[x,y,z]

  • 通过以上性质,从头到尾,每次找最近的一对数字的位置 i i i j j j a i = a j a_i=a_j ai=aj),执行以下操作:
    a i , a i + 1 , . . . , a j − 1 , a j 翻 转 一 遍 为 : a j − 1 , . . . , a i + 1 , a i , a j 再 翻 转 一 遍 : a j , a i , a i + 1 , . . . , a j − 1 a_i,a_{i+1},...,a_{j-1},a_j \\ 翻转一遍为:a_{j-1},...,a_{i+1},a_{i},a_j \\ 再翻转一遍:a_j,a_i,a_{i+1},...,a_{j-1} ai,ai+1,...,aj1,ajaj1,...,ai+1,ai,ajaj,ai,ai+1,...,aj1
    每次相当于在一个从头开始的数组操作,所以要记录他们的偏移量

AC代码:

#include <bits/stdc++.h>
#define ft first
#define sd second
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define seteps(N) fixed << setprecision(N)
#define endl "\n"
const int maxn = 6e5 + 10;
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
const ll mod = 1e9 + 7;
int t, n, a[maxn];
int cntb, b[maxn];
bool vis[maxn];
vector <int> ans;
vector <pii> op;
map <int, int> mp;
int bas;
void init() {
    mp.clear();
    ans.clear();
    op.clear();
    bas = cntb = 0;
    memset(vis, 0, sizeof(bool) * (n + 1));
}
bool pre() { //检测是否合理
    for (int i = 1; i <= n; i++) mp[a[i]]++;
    for (auto np : mp)
        if (np.second & 1)
            return false;
    return true;
}
void cal(int num) {
    int temp = num;
    for (int i = 1; i <= num; i++) {
        op.push_back({bas + temp, b[i]});
        temp++;
    }
    bas += temp; //记录偏移
    ans.push_back(temp); //记录答案
}
void solve() { //以下过程请自行手模一遍
    if (!pre()) {
        puts("-1");
        return;
    }
    for (int i = 1, j, k; i <= n; i++) {
        if (vis[i]) continue;
        for (j = i + 1; j <= n; j++) {
            if (vis[j] || a[i] != a[j]) continue;
            cntb = 0;
            for (k = i; k <= j; k++)
                if (!vis[k])
                    b[++cntb] = a[k];
            break;
        }
        if (j == i + 1) {
            vis[i] = vis[j] = true;
            bas += 2;
            ans.push_back(2);
            continue;
        }
        cal(cntb - 1);
        cntb = 0;
        for (k = j - 1; k >= i + 1; k--) 
            if (!vis[k])
                b[++cntb] = a[k];
        b[++cntb] = a[i]; b[++cntb] = a[i];
        cal(cntb);
        vis[i] = vis[j] = true;
        bas += 2;
        ans.push_back(2);
    }
    cout << op.size() << endl;
    for (auto np : op) cout << np.first << " " << np.second << endl;
    cout << ans.size() << endl;
    for (auto np : ans) cout << np << " ";
    cout << endl;
}
int main() {
    cin >> t;
    while (t--) {
        cin >> n;
        for (int i = 1; i <= n; i++) cin >> a[i];
        init();
        solve();
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值