zoukankan      html  css  js  c++  java
  • [题解][笔记]lgP1368&最小表示法

    [题解][笔记]lgP1368&最小表示法

    原题链

    算法用途

    这个题就是要求在一个循环同构串中找出字典序最小的排列

    算法过程

    首先,因为这个数列可以把第一个元素一道最后一个去,所以我们把这个序列倍长,这样就不用对指针取模啥的,更加方便.
    接着来讲算法的主体.首先我们先假设有一个排列:(7 5 3 3 3 1 4 6),把这个排列倍长就变成:(7 5 3 3 3 1 4 6 7 5 3 3 3 1 4 6),然后最小表示法是有两个指针(不能相等),先假设两个指针分别为(pos1),(pos2),那么这(pos1)指针就代表的是倍长后的序列从(pos1)作为开头,到(pos1 - 1)作为结尾的序列,(pos2)同理.接着我们先考虑(pos1)指针所指的数大于(pos2)指针所指的数的情况,这时显然以(pos2)为开头的排列更优所以更新(pos1),就是把(pos1+1),如果(pos1)所指的元素小于(pos2)所指的元素也是同理.
    接下来重点讲讲如果(pos1)(pos2)所指的元素是一样的怎么办.对于上面的序列,当(pos1=3),(pos2 = 4)时就出现了两个指针所指的元素相等的情况,这时我们无法判断两个指针谁代表的序列更优,所以(pos1)(pos2)都往后跳一个,知道出现两个指针指着的元素不相等的时候为止,在举的例子中当两个指针向后跳了(2)次后所指的元素就不同了(实际实现的时候并不是直接变动指针的值,而是让指针加上一个向后移动的变化量).此时,(pos1=3+2=5,pos2=4+2=6),我们可以发现(pos2)所指的值小于(pos1)所指的值,所以(pos2)更优一些,并且在下标为(3~5)为开头的序列都不会是最有的,因为通过刚才的匹配我们得知下标为(6)为开头的才是最有的所以把(pos1)指针移动到下标(6)处.
    这就是算法的基本过程,还没看懂的可以看看代码有一点点注释

    代码实现

    #include <bits/stdc++.h>
    using namespace std;
    int n;
    int a[3000010];
    int main(){
    	scanf("%d",&n);
    	for(int i = 1;i <= n;i++){
    		scanf("%d",&a[i]);
    		a[i + n] = a[i];//把原序列倍长
    	}
    	int pos1 = 1,pos2 = 2,delta = 0,pos;
    	while(pos1 <= n && pos2 <= n){
    		delta = 0;//向后移动的变化量
    		while(a[pos1 + delta] == a[pos2 + delta])//如果指针指向的元素大小相等就一起往后跳
    			delta++;
    		if(a[pos1 + delta] > a[pos2 + delta])pos1 += delta + 1;//跳到当前的最优解
    		else pos2 += delta + 1;//调到当前的最优解
    		if(pos1 == pos2)pos2++;//两个指针不能相等
    	}
    	pos = min(pos1,pos2);//因为有可能会超过n所以去最小值
    	for(int i = pos;i <= n + pos - 1;i++){
    		printf("%d ",a[i]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    jvm原理----------4.Java虚拟机何谓垃圾及垃圾回收算法
    jvm原理----------5.垃圾收集器及内存分配策略
    jvm原理----------6.创建对象及对象的访问定位
    mysql的sql语句的常用的优化方式
    jvm内存原理及调优(完全总结)
    dubbo的负载均衡与重试机制
    File类
    异常的真实应用
    字符串转换功能
    Object类介绍
  • 原文地址:https://www.cnblogs.com/czy--blog/p/13892002.html
Copyright © 2011-2022 走看看