2020多校第1场A题【后缀数组+思维】

在这里插入图片描述


1. 首 先 我 们 发 现 每 个 后 缀 开 头 一 定 是 0 , 而 且 开 头 都 是 0.. [ 若 干 个 1 ] . . 0 这 种 格 式 , 按 照 字 典 序 的 排 序 方 式 那 么 如 果 两 个 0 之 间 的 1 越 少 字 典 序 就 越 小 。 例 如 a a a a a b = > 011110 , a a a b = > 0110 , 那 么 我 们 设 d i s [ i ] 就 是 第 i 位 开 始 的 往 后 延 申 有 多 少 个 是 和 开 头 字 母 相 同 的 , 如 a a a b = > d i s [ ] = { 3 , 2 , 1 , 1 } ; 那 么 d i s [ i ] 越 小 对 应 数 组 的 字 典 序 一 定 越 小 1.首先我们发现每个后缀开头一定是0,而且开头都是0..[若干个1]..0这种格式,按照字典序的排序方式那么如果两个0之间的1越少字典序就越小。例如aaaaab=>011110,aaab=>0110,那么我们设dis[i]就是第i位开始的往后延申有多少个是和开头字母相同的,如aaab=>dis[]=\{3,2,1,1\};那么dis[i]越小对应数组的字典序一定越小 1.00..[1]..0,01aaaaab=>011110,aaab=>0110,dis[i]i,aaab=>dis[]={3,2,1,1};dis[i]
2. 还 有 一 个 明 显 的 规 律 就 是 0 的 个 数 最 多 两 个 , 因 为 出 现 了 两 个 0 说 明 a b 和 字 母 已 经 完 全 出 现 了 , 后 面 字 母 的 B [ ] 数 组 的 值 就 不 变 了 , 那 么 我 们 可 以 对 整 个 串 求 一 遍 B [ ] 数 组 , 在 比 较 两 个 后 缀 的 时 候 : 我 们 先 比 较 d i s [ i ] 和 d i s [ j ] , 如 果 d i s [ i ] = = d i s [ j ] 那 么 我 们 就 比 较 后 面 的 一 截 , 根 据 字 典 序 的 定 义 比 较 第 一 个 不 相 同 的 位 置 就 可 以 了 , 那 么 我 们 就 要 求 i + d i s [ i ] 和 j + d i s [ j ] 后 面 的 l c p , 比 较 B [ i + l c p + d i s [ i ] ] 和 B [ j + l c p + d i s [ j ] ] 就 可 以 了 2.还有一个明显的规律就是0的个数最多两个,因为出现了两个0说明ab和字母已经完全出现了,后面字母的B[]数组的值就不变了,那么我们可以对整个串求一遍B[]数组,在比较两个后缀的时候:我们先比较dis[i]和dis[j],如果dis[i]==dis[j]那么我们就比较后面的一截,根据字典序的定义比较第一个不相同的位置就可以了,那么我们就要求i+dis[i]和j+dis[j]后面的lcp,比较B[i+lcp+dis[i]]和B[j+lcp+dis[j]]就可以了 2.00abB[]B[],dis[i]dis[j],dis[i]==dis[j]i+dis[i]j+dis[j]lcp,B[i+lcp+dis[i]]B[j+lcp+dis[j]]
3. 注 意 还 有 就 是 i + d i s [ i ] 会 大 于 n , 大 于 n 相 当 于 后 面 补 0 , 在 前 面 相 同 的 情 况 下 越 短 的 字 符 串 字 典 序 越 小 3.注意还有就是i+dis[i]会大于n,大于n相当于后面补0,在前面相同的情况下越短的字符串字典序越小 3.i+dis[i]n,n0,


#include <iostream>
#include <cstdio>
#include <stack>
#include <sstream>
#include <limits.h>
#include <vector>
#include <map>
#include <cstring>
#include <deque>
#include <cmath>
#include <iomanip>
#include <queue>
#include <algorithm>
#include <set>
#define mid ((l + r) >> 1) 
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define _for(i,a,b) for( int i = (a); i < (b); ++i)
#define _rep(i,a,b) for( int i = (a); i <= (b); ++i)
#define for_(i,a,b) for( int i = (a); i >= (b); -- i)
#define rep_(i,a,b) for( int i = (a); i > (b); -- i)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define hash Hash
#define next Next
#define count Count
#define pb push_back
#define f first
#define s second
using namespace std;
const int N = 2e5+10, mod = 1e9 + 9;
const int maxn = 2e5 + 10;
const long double eps = 1e-5;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) 
{
    read(first);
    read(args...);
}


char a[N];
int n;
int ord[N], pos[N], dis[N];

struct SA {
    int sa[maxn], ra[maxn], height[maxn];
    int t1[maxn], t2[maxn], c[maxn];
    void build(int *str, int n, int m) {
        str[n] = 0;
        n++;
        int i, j, p, *x = t1, *y = t2;
        for (i = 0; i < m; i++) c[i] = 0;
        for (i = 0; i < n; i++) c[x[i] = str[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 (j = 1; j <= n; j <<= 1) {
            p = 0;
            for (i = n - j; i < n; i++) y[p++] = i;
            for (i = 0; i < n; i++) if (sa[i] >= j) y[p++] = sa[i] - j;
            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] + j] == y[sa[i] + j]) ? p - 1 : p++;
            if (p >= n) break;
            m = p;
        }
        n--;
        for (int i = 0; i <= n; i++) ra[sa[i]] = i;
        for (int i = 0, j = 0, k = 0; i <= n; i++) {
            if (k) k--;
            j = sa[ra[i] - 1];
            while (str[i + k] == str[j + k]) k++;
            height[ra[i]] = k;
        }
        st_init(height, n);
    }
    int lg[maxn], table[23][maxn];
    void st_init(int *arr, int n) {
        if (!lg[0]) {
            lg[0] = -1;
            for (int i = 1; i < maxn; i++)
                lg[i] = lg[i / 2] + 1;
        }
        for (int i = 1; i <= n; ++i)
            table[0][i] = arr[i];
        for (int i = 1; i <= lg[n]; ++i)
            for (int j = 1; j <= n; ++j)
                if (j + (1 << i) - 1 <= n)
                    table[i][j] = min(table[i - 1][j], table[i - 1][j + (1 << (i - 1))]);
    }
    int lcp(int l, int r) {
        l = ra[l], r = ra[r];
        if (l > r) swap(l, r);
        ++l;
        int t = lg[r - l + 1];
        return min(table[t][l], table[t][r - (1 << t) + 1]);
    }
} sa;

bool cmp(int i, int j) {
    if (dis[i] != dis[j]) return dis[i] < dis[j];

    if (i + dis[i] > n) return true;
    if (j + dis[j] > n) return false;
    int lcp = sa.lcp(i + dis[i], j + dis[j]);
    return pos[i + lcp + dis[i]] < pos[j + lcp + dis[j]];
}

int main()
{
    while(cin >> n >> a)
    {
        int pa = -1, pb = -1;
        for(int i = 0; i < n; ++ i)
            if(a[i] == 'a')
            {
                if(pa == -1) pos[i] = 0;
                else pos[i] = i - pa + 1;
                pa = i;
            }
            else 
            {
                if(pb == -1) pos[i] = 0;
                else pos[i] = i - pb + 1;
                pb = i;
            }
        pa = pb = -1;
        for(int i = n - 1; i >= 0; -- i)
          if(a[i] == 'a')
          {
              if(pb == -1) dis[i + 1] = n - i;
              else dis[i + 1] = pb - i;
              pa = i;
          }
          else 
          {
              if(pa == -1) dis[i + 1] = n - i;
              else dis[i + 1] = pa - i;
              pb = i;
          }
          for(int i = 1; i <= n; ++ i) ord[i] = i;
          sa.build(pos,n,n+2);
          sort(ord+1,ord+1+n,cmp);
          for(int i = 1; i <= n; ++ i) printf("%d ",ord[i]);
          puts("");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值