poj 1743

题意:给出一个串,求两个不相交的长度相等的子串,使得对应位置的差相等。

题解:首先,假设串是a[0],a[1],...a[n],先作差,即a[1]=a[1]-a[0],a[2]=a[2]-a[1],a[i]=a[i]-a[i-1],然后我们求a[1],a[2],a[3],...a[n]的两个不相交的公共子串。

先将h数组求出来,然后二分子串长度,。。。。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #define maxn 20010
 5 using namespace std;
 6
 7 int n;
 8 int aa[maxn], sa[maxn], rk[maxn], ht[maxn], vv[maxn];
 9
10 void expand( int k, int sa[maxn], int rk[maxn], int tsa[maxn], int trk[maxn] ) {
11     for( int i=1; i<=n; i++ ) vv[rk[sa[i]]]=i;
12     for( int i=n; i>=1; i-- ) if( sa[i]>k ) tsa[vv[rk[sa[i]-k]]--]=sa[i]-k;
13     for( int i=n-k+1; i<=n; i++ ) tsa[vv[rk[i]]--]=i;
14     for( int i=1; i<=n; i++ ) trk[tsa[i]]=trk[tsa[i-1]]+(rk[tsa[i]]!=rk[tsa[i-1]]||rk[tsa[i]+k]!=rk[tsa[i-1]+k]);
15 }
16 void calcht() {
17     int k=0;
18     ht[sa[1]]=0;
19     for( int i=1; i<=n; i++ ) {
20         if( rk[i]==1 ) continue;
21         int j=sa[rk[i]-1];
22         while( aa[i+k]==aa[j+k] ) k++;
23         ht[i] = k;
24         if( k>0 ) k--;
25     }
26 }
27 void suffix() {
28     static int tsa[maxn], trk[maxn];
29     for( int i=1; i<=180; i++ ) vv[i]=0;
30     for( int i=1; i<=n; i++ ) vv[aa[i]]++;
31     for( int i=1; i<=180; i++ ) vv[i]+=vv[i-1];
32     for( int i=1; i<=n; i++ ) sa[vv[aa[i]]--]=i;
33     for( int i=1; i<=n; i++ ) rk[sa[i]]=rk[sa[i-1]]+(aa[sa[i]]!=aa[sa[i-1]]);
34     int *pa=sa, *pb=rk, *pc=tsa, *pd=trk;
35     for( int k=1; k<n; k<<=1,swap(pa,pc),swap(pb,pd) )
36         expand(k,pa,pb,pc,pd);
37     if( pa!=sa ) memcpy( sa, tsa, sizeof(sa) ), memcpy( rk, trk, sizeof(rk) );
38     calcht();
39 }
40 bool ok( int len ) {    //    len>=1
41     int top, minp, maxp;
42     top = minp = maxp = sa[1];
43     for( int i=2; i<=n; i++ ) {
44         if( ht[sa[i]]<len ) {
45             if( maxp-minp>=len ) return true;
46             top = minp = maxp = sa[i];
47         } else {
48             if( minp>sa[i] ) minp=sa[i];
49             if( maxp<sa[i] ) maxp=sa[i];
50         }
51     }
52     if( maxp-minp>=len ) return true;
53     return false;
54 }
55 int main() {
56     while( scanf("%d",&n)==1 ) {
57         if( n==0 ) break;
58         n--;
59         for( int i=0; i<=n; i++ )
60             scanf( "%d", aa+i );
61         for( int i=n; i>=1; i-- )
62             aa[i]=aa[i]-aa[i-1]+88;
63         suffix();
64         int lf=0, rg=n/2;
65         while( lf<rg ) {
66             int mid=(lf+rg+1)>>1;
67             if( ok(mid) ) lf=mid;
68             else rg=mid-1;
69         }
70         lf++;
71         printf( "%d\n", lf<5 ? 0 : lf  );
72     }
73 }

时间: 2024-10-23 00:56:03

poj 1743的相关文章

POJ 1743 Musical Theme (后缀数组)

题目大意: 刚才上88个键弹出来的音符. 如果出现重复的,或者是高一个音阶的重复的都算. 思路分析: 具体可以参考训练指南222. height数组表示按照排序后的sa最近的两个后缀的最长前缀. 将height 分块.然后二分答案,二分答案之后去判断是否满足. 要考虑到不重合,还有大于5. 所以二分的时候要从5开始,然后判断的时候要加一个 up - down >len #include <cstdio> #include <iostream> #include <alg

poj 1743 最长不重叠重复子串 后缀数组+lcp+二分

题比较容易读懂,但是建模需动点脑子: 一个子串加常数形成的子串认为跟子串相同,求最长不重叠重复子串 题目中说 is disjoint from (i.e., non-overlapping with) at least one of its other appearance(s) 意味着不能重叠,举个例子 1, 2,3,  52, 53,54 1,2, 3和 52, 53,54满足题意,差值为51 枚举差值肯定不行------看了题解明白的:: 后项减去前一项得到: 1,1,1,49,1,1  

Poj 1743 Musical Theme (后缀数组+二分)

题目链接: Poj  1743 Musical Theme 题目描述: 给出一串数字(数字区间在[1,88]),要在这串数字中找出一个主题,满足: 1:主题长度大于等于5. 2:主题在文本串中重复出现(或者经过调转出现,调转是主题同时加上或者减去同一个整数) 3:重复主题不能重叠 解题思路: 求调转重复出现的子串,那么主题之间的差值一定是不变的.可以求文本串s中相邻两个数的差值,重新组成一个新的文本串S,然后找S后缀串中最长公共不重叠前缀.rank相邻的后缀串,公共前缀一定最长,但是有可能重叠.

POJ 1743 后缀数组:求最长不重叠子串

数据:这题弄了好久,WA了数十发,现在还有个例子没过,可却A了,POJ 的数组也太弱了. 10 1 1 1 1 1 1 1 1 1 1 这组数据如果没有那个n-1<10判断的话,输入的竟然是5,我靠-- 思路:这个题目关键的地方有两个:第一,重复的子串一定可以看作是某两个后缀的公共前缀,第二,把题目转化成去判定对于任意的一个长度k,是否存在长度至少为k的不重叠的重复的子串. 转化成判定问题之后,就可以二分去解答了.在验证判定是否正确时,我们可以把相邻的所有不小于k的height[]看成一组,然后

poj 1743 Musical Theme(男人八题&amp;后缀数组第一题)

Musical Theme Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 17298   Accepted: 5939 Description A musical melody is represented as a sequence of N (1<=N<=20000)notes that are integers in the range 1..88, each representing a key on the

[poj 1743]后缀数组例题

题目链接:http://poj.org/problem?id=1743 首先,musical theme只与前后位置的增减关系有关,而与绝对的数值无关,因此想到做一次差分. 然后对于差分后的数组,找到最长的出现两次(或两次以上)的一个子串即可.这个如果说两个子串可以交叉的话就好做了,直接取height的最大值即可,但是题目要求不能交叉,前几天一位师兄讲课刚讲了,可以用二分做.对于一个指定长度L,判断它是否可行,就用这个L去划分height数组,对于每个部分的分别看看最远的两个是否没有交叉就可以了

POJ 1743 Musical Theme(后缀数组+二分答案)

[题目链接] http://poj.org/problem?id=1743 [题目大意] 给出一首曲子的曲谱,上面的音符用不大于88的数字表示, 现在请你确定它主旋律的长度,主旋律指的是出现超过一次, 并且长度不小于5的最长的曲段,主旋律出现的时候并不是完全一样的, 可能经过了升调或者降调,也就是说, 是原来主旋律所包含的数字段同时加上或者减去一个数所得, 当然,两段主旋律之间也是不能有重叠的,现在请你求出这首曲子主旋律的长度, 如果不存在请输出0. [题解] 首先要处理的是升调和降调的问题,由

POJ 1743 Musical Theme 后缀数组 最长重复不相交子串

Musical ThemeTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://poj.org/problem?id=1743 Description A musical melody is represented as a sequence of N (1<=N<=20000)notes that are integers in the range 1..88, each representing a key on the piano. It

POJ 1743 (后缀数组+不重叠最长重复子串)

题目链接: http://poj.org/problem?id=1743 题目大意:楼教主の男人八题orz.一篇钢琴谱,每个旋律的值都在1~88以内.琴谱的某段会变调,也就是说某段的数可以加减一个旋律范围的值.问这个谱子内最长不重叠的重复部分大小. 解题思路: 网上题解已经泛滥的题.很多细节都被先辈大神总结了. 在当年后缀数组还不是热门的时候,这题确实是神题. 首先对于旋律变调的处理: 比如123,123,ans=3. 变调之后:456,123,ans=0?不ans=3. 所以不能使用旋律的初始

poj 1743 Musical Theme【后缀自动机】

不是很神的一道题,一般. 先差分,最后答案需要+1. 一个right集的len即为该right集的最长相同后缀,考虑到不能重复,所以处理一下该right集的最大与最小的ri,最后答案ans=max(ans,min(r[i]-l[i],len[i])) poj的g++比较恶心,卡空间,卡时间. 用c++交即可. #include<iostream> #include<cstdio> #include<cstdlib> #include<string> #inc