• ARC110F Esoswap 解题报告


    ARC110F Esoswap 解题报告:

    题意

    给定一个位置与值域均为 \([0,n-1]\) 排列 \(p\),可以多次操作,对 \(x\) 操作可以交换 \(p_x\)\(p_{(x+p_x)\bmod n}\),在 \(2\times 10^5\) 次操作内将排列排序。

    \(1\leqslant n\leqslant 100\)

    分析

    小清新(?)题。

    考虑将序列转为降序排列,再转为升序排列。(我也不知道我咋想到的)

    先考虑降序排列转为升序排列,可以增量法,每次维护一个升序后缀 \((i,n)\),将 \(1\) 所在的位置放到序列的最后面,然后将 \(i\)\(1\) swap(因为 \(i\) 的位置为 \(n-i-1\)),然后再把 \(1\) 和后面的 \(0\) swap 即可。

    算一下操作次数,是 \(\sum (n-i-2+1+1)=\frac{n(n-1)}{2}\) 次。

    然后是把普通排列转为降序排列。

    考虑仍然维护一个降序后缀 \((i,n)\),每次不断操作位置 \(i\) 直到其值为 \(n-i-1\),由于一次操作一定不会跳到

    由于一个位置上每种数字只会出现一次(在操作这个位置之前之后这个位置都不会被影响,而操作的时候每个数字都最多会被移动一次,不可能到能回来),而且合法的值 \(x\) 一定满足 \(n-x-1\) 小于等于位置,于是操作次数上界应该是 \(\frac{n(n+1)}{2}\)

    于是总操作次数是严格 \(n^2\) 的,时间复杂度与其同阶。

    代码

    #include<stdio.h>
    #include<vector>
    using namespace std;
    const int maxn=105;
    int n;
    int a[maxn];
    vector<int>ans;
    void solve(int x){
    	ans.push_back(x),swap(a[x],a[(x+a[x])%n]);
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=0;i<n;i++)
    		scanf("%d",&a[i]);
    	for(int i=n-1;i>=0;i--)
    		while(a[i]!=n-i-1)
    			solve(i);
    	for(int i=n-1;i>=0;i--){
    		for(int j=i+1;j<n-1;j++)
    			solve(j);//move 1
    		solve(i);//swap i 0
    		solve(i);//swap 1 0
    	}
    	printf("%d\n",ans.size());
    	for(int i=0;i<ans.size();i++)
    		printf("%d\n",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    Ansible facts
    K8S基础概念
    Ansible CMDB
    Docker 核心技术与实现原理
    如何在 Centos7 中使用阿里云的yum源
    一篇文全面了解DevOps:从概念、关键问题、兴起到实现需求
    关于操作stream流
    service not available now, maybe disk full, CL: 0.95 CQ: 0.95 INDEX: 0.95, maybe your broker mach
    AOP的底层实现,动态代理和cglib代理
    模拟浏览器加载静态资源
  • 原文地址:https://www.cnblogs.com/xiaoziyao/p/15789180.html
Copyright © 2020-2023  润新知