首页 > 其他分享 >ABC240Ex Sequence of Substrings

ABC240Ex Sequence of Substrings

时间:2024-05-05 21:33:21浏览次数:14  
标签:ABC240Ex Sequence int rx sqrt Substrings fd LIS log

ABC240Ex Sequence of Substrings

LIS 的好题改编。

约定

\(S(l,r)\) 为字符串 \(s\) 中第 \(l\) 位到底 \(r\)​ 位。

\(S(l,r)<S(x,y)\) 为字符串中 \([l,r]\) 的子串字典序比 \([x,y]\) 的子串小。

前置

LIS 的 \(n\log n\) 求法。

题解

我们考虑按照类似于朴素 LIS 的方式设状态,\(f[l][r]\) 表示 \([l,r]\) 这个区间作为当前选的最后一个划分,所得到的 LIS 最大值。

显然有转移:

\[f[l][r]=\max(f[x][y])+1 \]

要求 \(S(x,y)<S(l,r)\)。

我们可以使用一个很经典的判断两个字符串字典序大小的技巧,先使用 hash+二分 求出 LCP(最长公共前缀),然后用比较 LCP 的下一位求字典序大小。

对于方程里的 \(\max\) 操作,类似于 LIS 的 \(n\log n\) 做法维护一个 \(g\) 数组,之前 \(g[i]\) 表示 LIS 为 \(i\) 的最小数字,同时 \(g\) 数组有单调递增的性质。现在还是维护这样的一个 \(g\) 数组,\(g[i]\) 表示 LIS 为 \(i\) 的字典序最小区间,\(g[i]\) 可以用一个 pair 类型维护。

当然为了方便,笔者把数组变成了 set,维护相同的东西,方便直接使用 lower_bound 查询。

每一个 \(f[l][r]\) 都要做一次上述转移,转移复杂度包含:\(g\) 数组查找的 \(O(\log n)\),每次的查找的比较 \(O(\log n)\),共 \(O(\log^2 n)\)。总共复杂度 \(O(n^2\log^2 n)\)。

这个复杂度是肯定过不了的,我们考虑从这题的性质上去优化。

每一个 \(S(l,r)\) 肯定是从一个比他小的串 \(S(x,y)\) 转移过来的,我们可以分两种情况讨论:

  1. \(S(l,r)\) 靠长度比 \(S(x,y)\) 大。
  2. \(S(l,r)\) 通过字符比较比 \(S(x,y)\)​ 大。

考虑通过 2 类型的方式转移,那么 \(S(l,r)\) 的长度肯定小于等于 \(S(x,y)\)。

考虑通过 1 类型做贡献的子串的最大长度是 \(B\)。显然 \(B\) 肯定是从 \(1\) 开始累加起来的,那么前面肯定出现过长度为 \(B-1,B-2,B-3,\cdots,1\) 通过 1 类型转移的子串,他们总共的长度为 \(\frac{(1+B)\times B}{2}\),满足

\[\frac{(1+B)\times B}{2} \leq n \]

解得

\[B \leq \sqrt{2n} \]

说明了什么呢?

通过 1 类型做贡献的子串最大长度是 \(\sqrt{2n}\),通过 2 类型做贡献的子串长度小于等于最大子串长度。

那么我们每次只需要求子串长度在 \(\sqrt{2n}\) 以内状态,即只需要求满足 \(r-l+1\leq \sqrt{2n}\) 所有 \(f[l][r]\)。

时间复杂度降至 \(O(n\sqrt n \log^2 n)\)。

擦一把汗还是可以过的,信友队高级组 T1 和这题重了,实测也可以跑过。

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

#define mod 998244353

const int maxn=2e4+5e3+5;

#define ll long long
#define pii pair<int,int>
#define S second
#define F first

int n,B;
char s[maxn];

int ans;
ll sum[maxn],base[maxn];

unordered_map<int,int>f[maxn];

inline ll gt(int r,int l)
{
    return (sum[r]-sum[l-1]*base[r-l+1]%mod+mod)%mod;
}
inline bool cmps(int x,int rx,int y,int ry)
{
    return gt(rx,x)==gt(ry,y);
}
inline bool cmp(int x,int rx,int y,int ry)
{
    int l=1,r=min(rx-x+1,ry-y+1),ans=0;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(cmps(x,x+mid-1,y,y+mid-1)) l=mid+1,ans=mid;
        else r=mid-1;
    }
   if(ans==min(rx-x+1,ry-y+1)) return rx-x+1<ry-y+1;
    return s[x+ans]<s[y+ans];
}

struct node
{
    int l,r,w;
    bool operator<(const node a)const{return cmp(l,r,a.l,a.r);}
};
set<node>st;
pii fd[maxn];

int main()
{
    scanf("%d",&n);
    B=sqrt(2*n);
    base[0]=1;for(int i=1;i<=n;i++) base[i]=base[i-1]*113%mod;
    scanf("%s",s+1);
    for(int i=1;i<=n;i++) sum[i]=(sum[i-1]*113+s[i]-'0'+mod)%mod;
    for(int L=1;L<=n;L++)
    {
        for(int R=L;R<=n&&R<=L+B;R++)
        {
            auto it=st.lower_bound({L,R,0});
            if(it!=st.begin()) f[L][R]=(--it)->w+1;
            else f[L][R]=1;
        }
        for(int j=L;j;j--)
        {
            if(L-j+1>B) break;
            if(fd[f[j][L]].F==0)
            {
                st.insert({j,L,f[j][L]});
                fd[f[j][L]]={j,L};
            }
            else if(cmp(j,L,fd[f[j][L]].F,fd[f[j][L]].S))
            {
                st.erase({fd[f[j][L]].F,fd[f[j][L]].S,f[j][L]});
                st.insert({j,L,f[j][L]});fd[f[j][L]]={j,L};
            }
        }
    }
    printf("%d",st.size());
}

标签:ABC240Ex,Sequence,int,rx,sqrt,Substrings,fd,LIS,log
From: https://www.cnblogs.com/binbinbjl/p/18173920

相关文章

  • [题解]P4597 序列 sequence
    P4597序列sequence是CF13CSequence的加强版,\(N\leq5*10^5\)。如果想了解\(O(N^2)\)的DP解法请看此文。给定\(N\)个数,每次操作可以选其中一个数\(+1\)或\(-1\)。请问要让这个数列不降,最少需要多少次操作?看到数据范围发现不能用\(O(N^2)\)的dp了,需要换一种思路。我们用类......
  • [题解]CF13C Sequence
    CF13CSequence给定\(N\)个数,每次操作可以选其中一个数\(+1\)或\(-1\)。请问要让这个数列不降,最少需要多少次操作?我们用DP解决。对\(a\)从小到大排序,存在\(c\)中。我们用\(f[i][j]\)表示让前\(i\)个元素满足条件,而且这些元素最大值不超过\(c[j]\)的最小操作次数。状态转移方......
  • CF1966D Missing Subsequence Sum 题解
    题意:给定\(n(n\le10^6)\)和\(k(k\len)\)。构造一个长度小于等于\(25\)的序列\(a\)满足:1.不存在一个子序列的和为\(k\)。2.对于\(1\lei\len,i\nek\),存在一个子序列的和为\(i\)。看到长度为\(25\),首先肯定会想到二进制。那么我们先构造出一个序列\([2^......
  • [atcoder 349] [F - Subsequence LCM]
    SOSDP学习笔记Linkhere:代码:importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.math.BigInteger;importjava.util.*;publicclassMain{staticintn;staticlongm;staticlong[]a;......
  • pack_sequence和pad_sequence(未整理)
    【pad/packsequence】:https://blog.csdn.net/tcn760/article/details/124982295https://blog.csdn.net/xinjieyuan/article/details/108562360https://zhuanlan.zhihu.com/p/342685890【pad/packsequence处理通过collate_fn结合到dataloader里】https://pytorch.org/docs......
  • F - Subsequence LCM
    F-SubsequenceLCMProblemStatementYouaregivenasequenceofpositiveintegers$A=(A_1,A_2,\dots,A_N)$oflength$N$andapositiveinteger$M$.Findthenumber,modulo$998244353$,ofnon-emptyandnotnecessarilycontiguoussubsequencesof$A$suc......
  • [491] Non-decreasing Subsequences
    算法助手用户:这个题目有什么好的思路吗?“Givenanintegerarraynums,returnallthedifferentpossiblenon-decreasingsubsequencesofthegivenarraywithatleasttwoelements.Youmayreturntheanswerinanyorder.”我的代码是这样的:/**@lcapp=leetcod......
  • 深度学习-nlp-NLP之sequence2sequence--73
    目录1.sequence2sequence任务特点2.编码器与解码器参考:https://zhuanlan.zhihu.com/p/38816145sequence2sequence模型发展到今天,根据不同任务有着不同的变体。了解了最基本的框架之后,再看别的模型就没有太大问题了。1.sequence2sequence任务特点输入输出时不定长的。比......
  • 读论文-序列感知推荐系统(Sequence-Aware Recommender Systems)
    前言今天读的论文为一篇于2018年发表在(ACMcomputingsurveys(CSUR))的论文,这篇文章主要讲述了序列感知推荐系统(Sequence-AwareRecommenderSystems)的研究和应用。文章首先介绍了推荐系统在实际中的应用背景,然后指出了传统推荐系统在处理用户行为序列信息方面的局限性。接着,文......
  • py_trees Sequence节点参数: memory=True | False
    Python行为树py_trees的一种注意情况:memory=True|Falsepy_trees…composites.Sequence(name=“root”,memory=True)官方文档是这样写的Ifconfiguredwithmemoryandachildreturnedwithrunningontheprevioustick,itwillproceeddirectlytotherunn......