其他分享
首页 > 其他分享> > [SNOI2019] 字符串 - 思维

[SNOI2019] 字符串 - 思维

作者:互联网

Description

给定一个长度为 \(n \le 10^6\) 的字符串,设删掉第 \(i\) 个字符后得到的字符串为 \(s_i\),按照字典序对 \(s_1,s_2,...,s_n\) 排序。如果两个字符串相等,那么认为编号小的字符串字典序更小。

Solution

对于原串 \(a\),预处理出对于每一个 \(i\),最小的 \(j>i\) 使得 \(a_i \neq a_j\)。

对于 \(i<j\) 的两个串,如果离 \(a_i\) 最近的不同的数是 \(a_k\)。

如果 \(j<k\),则证明编号为 \(i,j\) 的两个串完全相同,因此 \(i\) 排在 \(j\) 前面。

如果 \(j \ge k\),观察下面的示意图,可以发现,此时 \(i\) 排在 \(j\) 前面当且仅当 \(a_k < a_i\)。

------x--
------x--
  i    j
-----x--
------x-

至于如何预处理出每个 \(i\) 对应的 \(k\),我们只需要倒序暴力递推即可。

#include <bits/stdc++.h>
using namespace std;

#define int long long 
const int N = 1000005;

char a[N];
int f[N],id[N],n;

bool cmp(int i,int j)
{
    if(i>j) 
    {
        swap(i,j);
        int k=f[i];
        if(j<k) return 0;
        if(a[k]<a[i]) return 0;
        return 1;
    }
    else
    {
        int k=f[i];
        if(j<k) return 1;
        if(a[k]<a[i]) return 1;
        return 0;
    }
    
}

signed main()
{
    ios::sync_with_stdio(false);

    cin>>n>>a+1;
    
    for(int i=1;i<=n;i++) id[i]=i;
    
    f[n+1]=n+1;
    for(int i=n;i>=1;--i)
    {
        if(a[i]!=a[i+1]) f[i]=i+1;
        else f[i]=f[i+1];
    }

    sort(id+1,id+n+1,cmp);
    for(int i=1;i<=n;i++) 
    {
        cout<<id[i]<<" ";
    }

    //system("pause");
}

标签:思维,int,long,--,字符串,------,SNOI2019,id
来源: https://www.cnblogs.com/mollnn/p/13752785.html