bzoj2882工艺(最小表示法)

O(nlogn)的做法十分显然,有三种可以做到O(nlogn)的:1、最容易的想法:把串扩展成两倍,然后跑一遍SA求后缀数组。2、求后缀同样也可以用SAM去求解,用map存一下。3、最暴力的方法:直接二分+hash比较第一位不同的。

其实这题想要让我们用最小表示法求解,然而我不会就来学一下。很容易发现这样一个规律,如果存在s[i+k]>s[j+k],那么s[i...i+k]开头的都不会是最小表示法开头,因为s[i...i+k]=s[j...j+k],所以从s[i...i+k]开头的串都会经过这里。出现这种情况,直接i+=k即可。又简便又好写,不过这种方法很容易忘。

#include<bits/stdc++.h>
using namespace std;
const int N=6e5+7;
int n,a[N];
int solve()
{
    int i=1,j=2;
    while(i<=n&&j<=n)
    {
        int k=0;
        while(j+k<=2*n&&a[i+k]==a[j+k])k++;
        if(j+k>2*n)break;
        if(a[i+k]>a[j+k])i=max(j,i+k+1),j=i+1;
        else j+=k+1;
    }
    return min(i,j);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),a[i+n]=a[i];
    int pos=solve();
    for(int i=pos;i<pos+n;i++)printf("%d ",a[i]);
}

原文地址:https://www.cnblogs.com/hfctf0210/p/10848320.html

时间: 2024-10-09 08:10:12

bzoj2882工艺(最小表示法)的相关文章

bzoj2882 工艺

2882: 工艺 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 488  Solved: 212 [Submit][Status][Discuss] Description 小敏和小燕是一对好朋友. 他们正在玩一种神奇的游戏,叫Minecraft. 他们现在要做一个由方块构成的长条工艺品.但是方块现在是乱的,而且由于机器的要求,他们只能做到把这个工艺品最左边的方块放到最右边. 他们想,在仅这一个操作下,最漂亮的工艺品能多漂亮. 两个工艺品美观的

HDU 4162 Shape Number(字符串,最小表示法)

HDU 4162 题意: 给一个数字串(length <= 300,000),数字由0~7构成,求出一阶差分码,然后输出与该差分码循环同构的最小字典序差分码. 思路: 第一步是将差分码求出:s[i] = (s[i] - s[i+1] + 8) % 8; 第二步是求出最小字典序的循环同构差分码,我之前没注意到字符串规模..直接用set做,MLE+TLE... 正确的方式应该是一种O(n)的解法,即最小表示法.//关于最小表示法的证明与详述请参考最小表示法:) 最小表示法算法: 初始时,i=0,j=

最小表示法(模板)

最小表示法就是对于一个循环字符串,其字典序最小的状态: 显然任意一个循环串的最小表示法是唯一的,那么可以同过比较两个循环串的最小表示法来判断它们是否相同: 对于朴素算法: 初始化:i = 0, j = 1, k = 0; 若 s[i] < s[j],j++: 若 s[i] > s[j],i = j, j++: 若 s[i] == s[j],则 k++,直至 s[i + k] != s[j + k] 对于 s[i + k] < s[j + k],j++: 否则 i = j, j++: 返回

USACO 5.5.2 字符串的最小表示法

这道题是最小表示法的一个应用, 代码如下: /* ID: m1500293 LANG: C++ PROG: hidden */ #include <cstdio> #include <algorithm> #include <cstring> using namespace std; char s[100000 + 100]; int len; int mins(char s[], int len) { int i=0, j=1, k=0; while(i<len

【枚举】【最小表示法】XVII Open Cup named after E.V. Pankratiev Stage 14, Grand Prix of Tatarstan, Sunday, April 2, 2017 Problem F. Matrix Game

给你一个n*m的字符矩阵,将横向(或纵向)全部裂开,然后以任意顺序首尾相接,然后再从中间任意位置切开,问你能构成的字典序最大的字符串. 以横向切开为例,纵向类似. 将所有横排从大到小排序,枚举最后切开的位置在哪一横排,将这一排提到排序后的字符串数组最前面,求个"最大表示法",如果最大表示法的位置恰好在第一排的位置,那么可以用来更新答案. 如果不在第一排的位置,那么其所构成的仍然是合法的串,而且一定不会影响答案. 这是一个最小表示法的板子. #include<cstdio>

BZOJ 2176 Strange string 最小表示法

题目大意:给定一个串S,求最小表示法 n<=1000W,实在不敢写后缀自己主动机,就去学了最小表示法= = 记得用unsigned char不然WA= = 数据真是逗- - #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 10001000 using namespace std; int n; unsigned char s[

循环字符串最大最小表示法模版

循环字符串最大最小表示法模版 定义字符串abcde和cdeab同构,因为abcde转两格即为cdeab,该字符串称为循环字符串. 循环字符串的字典序最小的同构字符串称为最小表示,最大表示同理. 这里只给模版,以后再深究. int getMin(char *s) ///返回首位置 { int n=strlen(s); int i=0,j=1,k=0; while(i<n&&j<n&&k<n){ int t=s[(i+k)%n]-s[(j+k)%n]; if(

hdu 2609 How many 最小表示法

How many Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1248    Accepted Submission(s): 486 Problem Description Give you n ( n < 10000) necklaces ,the length of necklace will not large than 100

51nod1282(最小表示法&amp;&amp;枚举)

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1282 题意:中文题目诶- 思路:指针不可转,刻盘可转,显然,对于两组指针,当且仅当它们所有对应相邻指针间距都相等时是满足题意的: 先得到指针间距,因为刻盘可转,相当于循环数组,可以先求一下最小表示法,然后再两两枚举所有情况,对于最小表示法相同的两组指针,计数加一: 代码: 1 #include <iostream> 2 #include <algori