首页 > 其他分享 >AT_joisc2015_h 题解

AT_joisc2015_h 题解

时间:2023-12-29 09:55:06浏览次数:38  
标签:joisc2015 int 题解 cntl 端点 区间 排序 回文

传送门

题意:给定长为 \(n\) 的字符串 \(s\),你可以选择一个区间,将区间内的字符从小到大排序,求可以得到的最长回文子串长度,字符集大小为 \(n\)。

很有意思的题目。

首先容易做到 \(O(n^3)\)。考虑怎么优化。

我们先考察排序的区间和回文区间的关系。

  1. 如果两个区间无交,那么显然排序不会对回文串长度有影响。
  2. 如果排序区间包含了回文区间,那么答案就是最多的相同字符数,容易求出。
  3. 剩下的情况可以根据两个区间的中点的关系分成两种,这两种可以通过把回文串翻转来转化,于是只用考虑一种。

不妨设排序区间的中点在回文串中点右侧,根据排序区间和回文串右半部分的关系,可以分为 4 种,但这 4 种可以一起考虑。(下面的图都来自 官方题解
img

具体地,对于前两种情况,我们枚举回文串中心,暴力往外拓展找最长的回文串,然后考虑两边的贡献;对于后两种情况,我们枚举排序区间左侧的前一个数作为的左端点,往右找到最近的比左端点前的数小的第一个数,那么最终回文串中心的一段都是这个数,然后再考虑两边的贡献。这时两种情况后面的处理大致相同了。

我们从左端往左找最长的不下降连续段,记录每个数的出现次数,然后从右端点开始往右扫。对于前两种情况,遇到小于左端点的数就停止;对于后两种情况,直到遇到比第一个遇到的比左端点小的数更小就停止。对于前两种情况,在扫描的过程中,两边的贡献就是右边从小到大第一个出现次数超过左边的数之前的数的个数;对于后两种情况,贡献就是比左端点小的数的个数加上右边从小到大第一个出现次数超过左边的数之前的数的个数(不算比左端点小的数)。

说起来比较抽象,看图就好理解了。
img
左侧有一个 \(2\)、两个 \(4\)、三个 \(6\),右边有两个 \(1\)、一个 \(2\)、三个 \(4\),右边的三个 \(4\) 已经比左侧的两个 \(4\) 要多了,那么能做贡献的就只有在中间的两个 \(1\),和两边的一个 \(2\)、两个 \(4\),回文串长度就是 \(3+2+3=8\)。

需要注意的是对于第一种情况,排序区间的右端点往右的部分也可能和左边形成回文串,提前预处理出 \(f[i][j]\) 表示从 \(i\) 往左,\(j\) 往右最长的相等串的长度即可。

复杂度 \(O(n^2)\)。

代码也还好。

const int N=3051;
int n,c;
int a[N],ans;
int f[N][N],cntl[N],cntr[N];
inline int calc(int l,int r,int lim=0){
    memset(cntl,0,sizeof(cntl));memset(cntr,0,sizeof(cntr));
    int L=l,maxn=0,cntmid=0,ansl=1,ansr=0;
    cntl[a[l]]++;
    while(a[L-1]>=a[L])cntl[a[--L]]++,ansl++;
    int posl=0,posr=a[L];
    for(int i=r;i<=n;i++){
        cntr[a[i]]++;
        if(a[i]<lim)return maxn;
        if(a[i]==lim)cntmid++;
        else if(cntr[a[i]]>cntl[a[i]]){
            while(posr>a[i]){
                ansl-=cntl[posr--];
            }
        }
        else{
            while(posl<=c&&cntl[posl]<=cntr[posl]){
                ansr+=cntl[posl++];
            }
        }
        int cur=min(ansr+cntr[posl],ansl);
        if(cur+cntmid==i-r+1)cur+=f[l-cur][i+1];
        maxn=max(maxn,2*cur+cntmid);
    }
    return maxn;
}
inline void solve(){
    for(int i=1;i<=n;i++){
        for(int j=i;j<=n;j++){
            if(a[i]==a[j])f[i][j]=f[i-1][j+1]+1;
            else f[i][j]=0;
        }
    }
    for(int i=1;i<=n;i++){
        ans=max(ans,2*f[i][i]-1+calc(i-f[i][i],i+f[i][i]));
    }
    for(int i=1;i<n;i++){
        ans=max(ans,2*f[i][i+1]+calc(i-f[i][i+1],i+1+f[i][i+1]));
    }
    for(int i=1;i<=n;i++){
        int minn=0;
        for(int j=i+1;j<=n;j++){
            if(a[j]<a[i]){
                minn=a[j];
                break;
            }
        }
        ans=max(ans,calc(i,i+1,minn));
    }
}
int main(){
    ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
    cin>>n>>c;
    for(int i=1;i<=n;i++)cin>>a[i];
    solve();
    reverse(a+1,a+n+1);
    for(int i=1;i<=n;i++)a[i]=c-a[i]+1;
    solve();
    sort(a+1,a+n+1);
    int cnt=0;
    for(int i=1;i<=n;i++){
        if(a[i]!=a[i-1])cnt=1;
        else cnt++,ans=max(ans,cnt);
    }
    cout<<ans<<endl;
    return 0;
}

标签:joisc2015,int,题解,cntl,端点,区间,排序,回文
From: https://www.cnblogs.com/Xttttr/p/17934104.html

相关文章

  • CF1835C Twin Clusters 题解
    题目链接点击打开链接题目解法很牛逼的构造题好像随也可以过长度为\(2^{k+1}\)的序列的不同区间有\(2^{2k+1}\)个,值域是\(4^k\),所以一定有解将\(a\)做一遍前缀和,那么问题转化成了找\(s_{r1}\opluss_{l1-1}=s_{r2}\opluss_{l2-1}\)先讲一讲具体做法:按照前\(k\)......
  • ICPC2021Kunming G Glass Bead Game 题解
    QuestionICPC2021KunmingGGlassBeadGame有\(n\)个玻璃珠,\(B_1,B_2,\cdots,B_n\)每一步你可以选择一个\(B_i\)移道第一个位置上,花费的代价为操作前\(B_i\)前面的玻璃珠的个数。已知每一步选择玻璃珠\(B_i\)的概率\(p_i\),问当\(m\rightarrow\infty\)时,在第\(......
  • ICPC2021Kunming G Find the Maximum 题解
    QuestionFindtheMaximum给出一个树,每个点有一个权值\(b_n\),求一条树上路径\(V\),要求\(\frac{\sum_{u\inV(-x^2+b_ux)}}{|V|}\)最大,其中\(x\)是自己选择的一个树Solution先转化一下\(\frac{\sum_{u\inV(-x^2+b_ux)}}{|V|}\),得到\[\frac{\sum_{u\inV(-x^2+b_......
  • vue前端node内存溢出问题解决
    前端项目运行时,如果经常运行慢,崩溃停止服务,报如下错误:FATALERROR:CALL_AND_RETRY_LASTAllocationfailed-JavaScriptheapoutofmemory(JavaScript堆内存不足) 原因:因为在Node中,通过JavaScript使用内存时只能使用部分内存(64位系统:1.4GB,32位系统:0.7GB),这个时候,如......
  • openssh升级对应问题解决方案
    问题1:./openssl:errorwhileloadingsharedlibraries:libssl.so.1.1:cannotopensharedobjectfile:Nosuchfileordirectory解决方案:cp/usr/local/openssl1.1.1/lib/libssl.so.1.1/lib64/cp/home/tydl/openssl-1.1.1u/libcrypto.so.1.1/lib64/ 问题2:/etc/ssh/s......
  • 「题解」Codeforces 1427G One Billion Shades of Grey
    感谢127的指导/ll\(|h_u-h_v|=\max(0,h_u-h_v)+\max(0,h_v-h_u)\),那么可以把它看成这样的问题:\[\min\{\sum_{(u,v)}\max(0,h_u-h_v+w_{u,v})c_{u,v}\}\]对偶一下,问题就变为:如果两个格子相邻就互相连容量为\(c_{u,v}=1\),费用为\(w_{u,v}=0\)的边,跑最大费用循环流。为了限......
  • 「题解」P9747 「KDOI-06-S」签到题
    一个区间合法的充要条件是存在\(x\)满足其为区间按位或,并且《\(x\)左侧所有数或起来》《\(x\)右侧所有数或起来》二者有其一为\(x\)。扫描线扫右端点,不同的按位或将左端点分为\(\logA\)个区间,对于每个区间\([l,r]\)先在区间按位或\(v\)在序列中存在位置的vector中......
  • CF396C On Changing Tree 题解
    CF396C考虑将贡献表示出来:\(\forallv\in\text{subtree}_u\),\(v\)会加上\(x-(dep_v-dep_u)k\),然后发现这个东西可以维护整棵子树,即把\(x,dep_u\timesk\)和\(dep_v\timesk\)分开计算,然后\(dep_v\)可以最后再管,就变为子树加,单点和了。用树状数组维护dfs序即可。......
  • TinyMCE富文本编辑器粘贴图片自动上传问题解决
    TinyMCE编辑器支持粘贴图片,但是自动会将图片转换成base64编码,这样将内容提交到后台,数据会很大。  图|TinyMCE本文内容配置TinyMCE(版本:5.10.0)向编辑器中粘贴图片自动上传到后台,以下为配置代码:tinymce.init({selector:'#textarea',plugins:'previewautolink......
  • Ping不通问题解决 windows 查看对端MAC地址 ARP -a
    Ping不通问题解决   Linux查看ARP信息指南(linux查看arp) ARP(地址解析协议)是TCP/IP协议提供的网络层协议,通过ARP可以查看网络层面上当前可连接的本地网络内每个主机的MAC地址。 ##查看系统的ARP信息 Linux系统中查看ARP信息的方法有很多,下面简单介绍几种常见的查......