zoukankan      html  css  js  c++  java
  • [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
  • 相关阅读:
    php 获取当前目录和当前文件夹
    学习笔记12(选做)
    学习笔记11
    OpenEuler 中C与汇编的混合编程
    OpenEuler中C语言中的函数调用测试
    学习笔记10
    电子公文传输系统验收3开发环境
    电子公文传输系统验收2功能测试
    socket编程
    socket课堂
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14113657.html
Copyright © 2011-2022 走看看