poj1743 Musical Theme(后缀数组)

题意:

给你N个数,他们之间的升降调可以定义为相邻两数之差,但旋律可以整体升阶或降阶,问最少五个数长的相同旋律。

心得:

这题可以说是很毒瘤了,WA了若干发终于A了,期间竟然还有RE。

先作差分数组,可以看出长度小于10的显然不够分剪枝减掉。

然后,二分枚举答案,L为0,R为N/2。

这题即求 不重复的最长公共子串,考虑到2 4 6 8 10作出差分数组为4个2,即最终答案大于等于4即可。

如果是重复的最长公共子串,只需输出height的最大值即可。

扫描二维码关注公众号,回复: 3369871 查看本文章

毕竟height的sa不相邻前缀最大值是相邻的最小值,则结果一定是sa相邻的。

细节部分:

①作差可以作出负的,考虑到1-88的旋律,对差分数组整体+90,这样元素就分布到0-200之间。

②差分数组的实际长度,加上后补0的长度,最后还是N,预处理sa数组与high数组要注意。

③C数组,基数排序临时存排名的数组别开小了,开200直接RE,我也不知道为啥。

④对于连续的high数组,只要让最末SA排名对应前缀起始位置tall和最初SA排名对应前缀起始位置low之间,差出一个二分的mid答案即可,即若s[3]-s[5]相同,s[6]-s[8]相同,且二者公共前缀长度为3,只需让tall-low≥(5-3+1)即可,则二者没有重叠部分。
对于aaaabb,aaaabc,aaaacc这种连续相同前缀,只需让最大-最小≥len即可。

 if(high[i]<mid)low=sa[i],tall=sa[i];
 else
 {
  low=min(low,sa[i]);
  tall=max(tall,sa[i]);
  if(tall-low>=mid){flag=1;break;}
 }

⑤二分的操作,除了while(r-l>1)if(judge(mid))l=mid;else r=mid; //l为最终答案以外,

又见到一个while(l<=r)if(flag)l=mid+1;else r=mid-1;//r为最终答案的写法

//这个可以理解成,比l小的都是可行解,比r大的都是不行解;

反过来说,小于等于r的都是可行解,即r是最大的可行解。

或者说,l-1也是最大的可行解,毕竟脱离循环是r=l-1;

思路来源:https://blog.csdn.net/crescent__moon/article/details/23201229

完整代码:

#include <iostream>
#include <algorithm> 
#include <string>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <bitset> 
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
const double eps=1e-7;
typedef long long ll;
#define vi vector<int> 
#define si set<int>
#define pii pair<int,int> 
#define pi acos(-1.0)
#define pb push_back
#define mp make_pair
#define lowbit(x) (x&(-x))
#define sci(x) scanf("%d",&(x))
#define scll(x) scanf("%lld",&(x))
#define sclf(x) scanf("%lf",&(x))
#define pri(x) printf("%d",(x))
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define per(i,j,k) for(int i=j;i>=k;--i)
#define mem(a,b) memset(a,b,sizeof(a)) 
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 20010;
int s[N],v[N];
int sa[N], t[N], t2[N], c[N], n;
int Rank[N], high[N],ans;
void build(int m)
{
    int i, *x = t, *y = t2;
    for(i = 0; i < m; i++) c[i] = 0;
    for(i = 0; i < n; i++) c[x[i] = s[i]]++;
    for(i = 1; i < m; i++) c[i] += c[i-1];
    for(i = n-1; i >= 0; i--) sa[--c[x[i]]] = i;
    for(int k = 1, p; k <= n; k<<=1, m=p) {
        p = 0;
        for(i = n-k; i < n; i++) y[p++] = i;
        for(i = 0; i < n; i++) if(sa[i] >= k) y[p++] = sa[i] - k;
        for(i = 0; i < m; i++) c[i] = 0;
        for(i = 0; i < n; i++) c[x[y[i]]]++;
        for(i = 1; i < m; i++) c[i] += c[i-1];
        for(i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
        swap(x, y);
        p = 1; x[sa[0]] = 0;
        for(i = 1; i < n; i++) {
            x[sa[i]] = (y[sa[i-1]] == y[sa[i]] && y[sa[i-1]+k] == y[sa[i]+k]) ? p-1 : p++;
        }
        if(p >= n) break;
    }
}
/* 
void get_high()
{
    int j,k=0;
    for(int i=0;i<n;++i)Rank[sa[i]]=i;
    for(int i=0;i<n-1;high[Rank[i++]]=k)
    for(k?k--:0,j=sa[Rank[i]-1];s[i+k]==s[j+k];k++);
    for(int i=0;i<n;++i)printf("%d:%d %d\n",i,sa[i],high[i]);
}*/
void get_height()//求height函数
{
    int i,j,k=0;
    for(i=1;i<n;i++)Rank[sa[i]]=i;//求rank函数
    for(i=0;i<n;high[Rank[i++]]=k)
        for(k?k--:0,j=sa[Rank[i]-1];s[i+k]==s[j+k];k++);
    //for(int i=0;i<n;++i)printf("%d:%d %d\n",i,sa[i],high[i]);
}

int solve(int t)
{
	int l=0,r=t/2,mid;//二分最终答案长度 
    bool flag=0;
	while(l<=r)
    {
     	mid=(l+r)>>1;
		int low=sa[1],tall=sa[1];
		flag=0;
		rep(i,2,n-1)
	    {
	     if(high[i]<mid)low=sa[i],tall=sa[i];
	     else
	     {
	     	low=min(low,sa[i]);
	     	tall=max(tall,sa[i]);
	     	if(tall-low>=mid){flag=1;break;}
	     }
	    }
	     if(flag)l=mid+1;
	     else r=mid-1;
	}
	return r>=4?r+1:0;
}
int main()
{
	while(scanf("%d",&n),n)
	{
	 for(int i=0;i<n;++i)scanf("%d",&v[i]);
	 if(n<10){puts("0");continue;}
	 for(int i=0;i<n-1;++i)s[i]=v[i+1]-v[i]+90;//最小负值-87 加90为正 
	 s[n-1]=0;
	 int maxi = 0;
	 for(int i = 0; i < n; i++)maxi = maxi > s[i] ? maxi : s[i];
     build(maxi+1);
     get_height();
     printf("%d\n",solve(n));
    }
   	return 0;
}

自己真是啥也不会啊,好好补题吧QAQ

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/82817769