• [atARC110F]Esoswap


    先构造使得$p_{i}$降序(即$p_{i}=n-1-i$),只需要从后往前,不断执行$i$操作直至合法即可

    正确性的证明:首先保证了$[0,n-i)$这些数字都已经出现,因此操作不会破坏已确定的数字的顺序

    同时,一个数字不会重复出现,因为若要与其交换后的位置再交换,仍需要其本身,显然不可能

    (特别的,对于0由于已经会在$n-1$上出现,因此不需要考虑)

    由于每一个位置上每一个数至多出现1次,因此至多$n^{2}$次操作即可

    再考虑如何把顺序调回来,先将一个后缀排好,然后考虑插入一个数$i$(后缀必然是$[0,i)$)

    考虑操作$p_{j}=1$的位置$j$,相当于将$j$向后挪1步,因此可以将1挪到末尾,又因为$i+p_{i}=n-1$,执行操作$i$将其与1交换,再将1与0交换即可

    例如:540123->540213->540231(把1挪到末尾)->510234(执行操作$i$)->501234(将1与0交换)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 105
     4 vector<int>ans;
     5 int n,a[N];
     6 void write(int k){
     7     ans.push_back(k);
     8     swap(a[k],a[(k+a[k])%n]);
     9 }
    10 int main(){
    11     scanf("%d",&n);
    12     for(int i=0;i<n;i++)scanf("%d",&a[i]);
    13     for(int i=n-1;i;i--)
    14         while (a[i]!=n-i-1)write(i);
    15     for(int i=n-2;i>=0;i--){
    16         for(int j=i+1;j<n-1;j++)write(j);
    17         write(i);
    18         write(i);
    19     }
    20     for(int i=0;i<n;i++)assert(a[i]==i);
    21     printf("%d
    ",ans.size());
    22     for(int i=0;i<ans.size();i++)printf("%d
    ",ans[i]);
    23 } 
    View Code
  • 相关阅读:
    第1章:路线图
    第0章:战胜恐惧和懊悔
    c++ 变量 定义 声明
    两个无符号数相减 可以得到负数
    c++ cast operator(类型转换操作符)
    C++中static 的使用方式,以及与c中的static的区别
    重载overload 重写override 重定义redefining
    用到位运算的题目
    C++ 虚函数表解析
    虚函数 动态绑定 实现方式是:虚函数表
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14113657.html
Copyright © 2020-2023  润新知