zoukankan      html  css  js  c++  java
  • [SNOI2019]字符串题解

    题目链接

    洛谷P5329

    sol

    题目意思很明确,但似乎不太好求。还是先看看部分分。

    10%数据

    (Theta(n^2log n)),暴力,先得10分。

    另20%数据

    发现一件事,在比较(s_i)(s_j)时,假设(i<j),从1到i-1这一段是一样的,从j+1到n是一样的,所以我们只要比较原串的i+1~ j和i ~j-1这两段就行。由于任意相邻两个都不相同,所以能(Theta(1))比较。

    另30%数据

    想到哈希,虽然哈希只能判等,但我们只要二分一下,找出两个字符串的最长公共前缀,再比较最长公共前缀的下一个位置就行。时间复杂度:(Theta(nlog^2n))

    最后40%数据

    到这应该很明朗了,两个后缀的最长公共前缀,立刻想到后缀数组。通过(nlog n)的预处理,可以(Theta(1))比较,再使用(Theta(nlog n))的快排就可以了。

    实测:TLE 60分

    后缀数组组似乎常数太大,不能通过。不过想一想我们需要什么,两个相邻后缀的最长公共前缀,可以设(h_i)为以i和i+1开头的后缀的最长公共前缀的长度,很明显(h_i>=h_{i-1}-1),其实相当于一起去掉两个开头字符,所以(h_i)一开始就赋值为(h_{i-1}-1),就可以(Theta(n))预处理h数组了,最后就可以直接排序了。虽然跑不过众多大佬的(Theta(n))算法,但也能通过了。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    #define cmp(a,b,c) (a+c<=n&&b+c<=n&&y[a]==y[b]&&y[a+c]==y[b+c])
    #define min(a,b) (a<b?a:b)//卡常
    const int maxn=1e6+10;
    char s[maxn];
    int ans[maxn],h[maxn],n;
    inline void write(int x) {//卡常
    	if(x>=10)write(x/10);
    	putchar(x%10^48);
    }
    void Swap(int &a,int &b) {//还是卡常
    	a^=b,b^=a,a^=b;
    }
    int cmp1(int a,int b) {//自定义比较方法
    	int f=0;
    	if(a>b)Swap(a,b),f=1;
    	if(h[a]>=b-a)return f^1;
    	return (s[a+h[a]+1]<s[a+h[a]])^f;
    }
    int t[maxn];
    void Qsort(int l,int r) {//手写归并排序,也是写后缀数组卡常留下的
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	Qsort(l,mid),Qsort(mid+1,r);
    	int i=l,j=mid+1,cnt=0;
    	while(i<=mid||j<=r) {
    		if((j>r)||(i<=mid&&cmp1(ans[i],ans[j])))t[cnt++]=ans[i++];
    		else t[cnt++]=ans[j++];
    	}
    	for(int i=0; i<cnt; i++)ans[i+l]=t[i];
    }
    int main() {
    	scanf("%d
    ",&n);
    	fread(s+1,1,n,stdin);//优读,写后缀数组卡常留下的
    	for(int i=1; i<n; i++) {//求h数组
    		h[i]=max(h[i-1]-1,0);
    		for(int j=i+1; s[i+h[i]]==s[j+h[i]]; h[i]++);
    	}
    	for(int i=1; i<=n; i++)ans[i]=i;//初始化
    	Qsort(1,n);
    	for(int i=1; i<n; i++)write(ans[i]),putchar(' ');
    	write(ans[n]),putchar('
    ');
    	return 0;
    }
    
  • 相关阅读:
    HashMap源码学习
    java线程池
    MySQL的MVCC
    volatile关键字学习
    ArrayList, Vector和CopyOnWriteArrayList对比学习
    曹工说Redis源码(3)-- redis server 启动过程完整解析(中)
    曹工说Redis源码(2)-- redis server 启动过程解析及简单c语言基础知识补充
    曹工杂谈:我们的应用,启动就要去其他服务拉数据,那其他服务挂了,我们就起不来了?
    程序员正确的提问方式(个人建议)
    曹工说Redis源码(1)-- redis debug环境搭建,使用clion,达到和调试java一样的效果
  • 原文地址:https://www.cnblogs.com/hht2005/p/11462809.html
Copyright © 2011-2022 走看看