poj3581 Sequence

2333

直接弃疗

第一遍搞出sa,去最小,注意sa>=3,(从1开始),后面直接输出,然后把前面剩下的复制,加到后面就好了,为什么这样呢?? %%% http://blog.163.com/just_gogo/blog/static/1914390652011823103842787/

还有,今天是找了一个神犇的后缀数组整理做的,感觉很爽(然后一天才4个题,感觉虚死了,代码能力什么的,,,没见过的样子)

后缀数组题目:http://blog.csdn.net/libin56842/article/details/46440923

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include<algorithm>
 5 #define N 100005
 6 #define inf 0x3f3f3f3f
 7 #define LL long long
 8 #define eps 1e-8
 9 using namespace std;
10 inline int ra()
11 {
12     int x=0,f=1; char ch=getchar();
13     while (ch<‘0‘ || ch>‘9‘) {if (ch==‘-‘) f=-1; ch=getchar();}
14     while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘; ch=getchar();}
15     return x*f;
16 }
17
18 const int maxn=400005;
19
20 int a[maxn],num[maxn],n,len,ans[maxn];
21 int sa[2][maxn],rank[2][maxn],v[maxn];
22 int p=0,q=1;
23 int find(int x)
24 {
25     int l=1,r=len-1;
26     while (l<=r)
27     {
28         int mid=l+r>>1;
29         if (num[mid]==x) return mid;
30         else if (num[mid]>x) r=mid-1;
31         else l=mid+1;
32     }
33 }
34 void cal_sa(int sa[maxn], int rank[maxn], int Sa[maxn], int Rank[maxn], int k)
35 {
36     for (int i=1; i<=n; i++) v[rank[sa[i]]]=i;
37     for (int i=n; i>=1; i--) if (sa[i]>k) Sa[v[rank[sa[i]-k]]--]=sa[i]-k;
38     for (int i=n-k+1; i<=n; i++) Sa[v[rank[i]]--]=i;
39     for (int i=1; i<=n; i++) Rank[Sa[i]]=Rank[Sa[i-1]]+(rank[Sa[i]]!=rank[Sa[i-1]] || rank[Sa[i]+k]!=rank[Sa[i-1]+k]);
40 }
41 void work()
42 {
43     for (int i=1; i<=n; i++) v[a[i]]++;
44     for (int i=1; i<=maxn-5; i++) v[i]+=v[i-1];
45     for (int i=1; i<=n; i++) sa[p][v[a[i]]--]=i;
46     for (int i=1; i<=n; i++) rank[p][sa[p][i]]=rank[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]);
47     for (int k=1; k<n; k<<=1,swap(p,q)) cal_sa(sa[p],rank[p],sa[q],rank[q],k);
48 }
49 void solve()
50 {
51     work(); int pos=0;
52     for (int i=1; i<=n; i++)
53         if (sa[p][i]>=3)
54         {
55             pos=sa[p][i]-1;
56             for (int j=pos+1; j<=n; j++) printf("%d\n",ans[a[j]]);
57             break;
58         } // while (1);
59     for (int i=1; i<=pos; i++) a[i+pos]=a[i];
60     n=pos*2; memset(v,0,sizeof(v)); work();
61 //    for (int i=1; i<=n; i++) printf("%d ",sa[p][i]); cout<<endl;
62     for (int i=1; i<=n; i++)
63         if (sa[p][i]>=2 && sa[p][i]<=pos)
64         {
65             pos=sa[p][i]-1; //cout<<"!!"<<pos<<"!!";
66             for (int j=pos+1; j<=n/2; j++) printf("%d\n",ans[a[j]]);
67             break;
68         }
69     for (int j=1; j<=pos; j++) printf("%d\n",ans[a[j]]);
70 }
71 int main(int argc, char const *argv[])
72 {
73     n=ra();
74     for (int i=n; i>=1; i--) a[i]=ra(),num[i]=a[i];
75     sort(num+1,num+n+1);
76     len=unique(num+1,num+n+1)-num;
77     for (int i=1; i<=n; i++) ans[find(a[i])]=a[i],a[i]=find(a[i]);
78     solve();
79     return 0;
80 }
时间: 2024-10-06 00:07:42

poj3581 Sequence的相关文章

POJ3581:Sequence(后缀数组)

Description Given a sequence, {A1, A2, ..., An} which is guaranteed A1 > A2, ..., An,  you are to cut it into three sub-sequences and reverse them separately to form a new one which is the smallest possible sequence in alphabet order. The alphabet or

POJ3581 Sequence(后缀数组)

题意:给一个串,串的第一个字符比后面的都大,要把它分成三段,然后反转每一段,求能得到的字典序最小的串是什么. 首先,第一段是可以确定的:把原串反转,因为第一个字符是最大的,它是唯一的,不存在反转串的后缀之间有包含关系,所以取最小的后缀这就是第一段的字符串: 然后后面两段,如果确定分割位置可以发现这两段字符串构成是一个从分割位置出发逆时针循环回来的串—— 即接下来要求的就是剩余部分的反转的最小表示,可以用后缀数组来做:把串加长一倍,答案就在最小的且长度大于等于原串长度的后缀了. 注意,分的段要非空

【后缀数组】poj3581 Sequence

考虑第一次切割,必然切割的是翻转后字典序最小的前缀,伪证: 若切割位置更靠前:则会导致第一个数翻转后更靠前,字典序必然更大. 若切割位置更靠后,则显然也会导致字典序更大. ↑,sa即可 对于第二次切割,有结论:将序列分割成两段再分别翻转得到的序列,可以看作是将两个原序列拼接得到的新序列中的某个字串翻转得到的序列. 因此计算新序列的sa,再从中选取字典序最小的合适的后缀即可. #include<cstdio> #include<cstring> #include<algorit

POJ 题目3581 Sequence(后缀数组)

Sequence Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 5738   Accepted: 1227 Case Time Limit: 2000MS Description Given a sequence, {A1, A2, ..., An} which is guaranteed A1 > A2, ..., An,  you are to cut it into three sub-sequences and

LeetCode OJ - Longest Consecutive Sequence

这道题中要求时间复杂度为O(n),首先我们可以知道的是,如果先对数组排序再计算其最长连续序列的时间复杂度是O(nlogn),所以不能用排序的方法.我一开始想是不是应该用动态规划来解,发现其并不符合动态规划的特征.最后采用类似于LRU_Cache中出现的数据结构(集快速查询和顺序遍历两大优点于一身)来解决问题.具体来说其数据结构是HashMap<Integer,LNode>,key是数组中的元素,所有连续的元素可以通过LNode的next指针相连起来. 总体思路是,顺序遍历输入的数组元素,对每个

1005 Number Sequence

Problem Description A number sequence is defined as follows: f(1) = 1, f(2) = 1, f(n) = (A * f(n - 1) + B * f(n - 2)) mod 7. Given A, B, and n, you are to calculate the value of f(n). Input The input consists of multiple test cases. Each test case co

HDU 5783 Divide the Sequence(数列划分)

HDU 5783 Divide the Sequence(数列划分) Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)   Problem Description - 题目描述 Alice has a sequence A, She wants to split A into as much as possible continuous subsequences, satisfy

HDU 3397 Sequence operation(线段树)

HDU 3397 Sequence operation 题目链接 题意:给定一个01序列,有5种操作 0 a b [a.b]区间置为0 1 a b [a,b]区间置为1 2 a b [a,b]区间0变成1,1变成0 3 a b 查询[a,b]区间1的个数 4 a b 查询[a,b]区间连续1最长的长度 思路:线段树线段合并.须要两个延迟标记一个置为01,一个翻转,然后因为4操作,须要记录左边最长0.1.右边最长0.1,区间最长0.1,然后区间合并去搞就可以 代码: #include <cstdi

HDU 3998 Sequence (最长递增子序列+最大流SAP,拆点法)经典

Sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1666    Accepted Submission(s): 614 Problem Description There is a sequence X (i.e. x[1], x[2], ..., x[n]). We define increasing subsequ