2023NOIP A层联测10 T4 子序列

题面及数据范围

Ps:链接来自accoderOJ。

考场2小时才做完 T1,抱着试一试的心态看了 T4,然后想到做法了,调了 1 个多小时没调除了,赛后发现数组开小了,因为与正解做法稍有不同,于是又调了一下午……

转移方程

设状压dp \(f[i][state][0/1]\) 是到第 \(i\) 个字母,\(state\) 中有两位标位了 \(1\) ,不妨设标 \(1\) 的是第 \(x\) 位和第 \(y\) 位表示使用了第 \(x\) 个和第 \(y\) 个字母(\(x<y\)),\(0\) 表示是 第 \(x\) 个字母是上一个字母,\(1\) 表示是第 \(y\) 个是上一个字母。

那么不难得到有如下转移

若 \(s[i]\) 是第 \(x\) 个字母:

\[f[i][state][0]=f[i-1][state][1]+1
\]

若 \(s[i]\) 是第 \(y\) 个字母:

\[f[i][state][1]=f[i-1][state][0]+1
\]

若 \(s[i]\) 都不是:

\[f[i][state][1]=f[i-1][state][1]\\
f[i][state][0]=f[i-1][state][0]
\]

统计答案

那我们要怎么样统计答案呢?

可以想到用 \(l-1\) 位置时与 \(r\) 时的同一个状态 \(state\) 作差求出最大长度。

观察一手性质,发现对于每一个状态而言,最靠近 \(l\) 的那个字母做开头一定可以得到最长,而结尾两者皆可,于是有:

若靠近的是第一个字母:

\[ans[i]=\max(f[r[i]][state][1],f[r[i]][state][0])-f[l[i]-1][state][1]
\]

Ps:第一个字母前面肯定接的是第二个字母。

若靠近的是第二个字母:

\[ans[i]=\max(f[r[i]][state][1],f[r[i]][state][0])-f[l[i]-1][state][0]
\]

预计时间复杂度:\(O(2^{26}n)\)

优化

这种复杂度暴力都心累,于是乎我们要优化。

dp 优化

先使用滚动优化,优化掉第 \(1\) 维,那么转移方程变成:

若 \(s[i]\) 是第 \(x\) 个字母:

\[f[state][0]=f[state][1]+1
\]

若 \(s[i]\) 是第 \(y\) 个字母:

\[f[state][1]=f[state][0]+1
\]

若 \(s[i]\) 都不是:

\[f[state][1]=f[state][1]\\
f[state][0]=f[state][0]
\]

由于 \(state\) 有效状态为 \(26\) 个字母中选 \(2\) 个字母不重复的状态,那么我们可以给每一个编号表示一个状态,即表示一种两个字母的方案,这样的编号有 \(C^2_{26}=325\) 个。

而且当前 \(s[i]\) 已经确定,相当于已经确定了 \(1\) 个字母,所以转移时枚举另外一个字母组成答案即可。

dp 时间复杂度优化至 \(T(25n)\)。

统计优化

但这样子我们同时也需要记录在 \(l-1\) 与 \(r\) 位置时 \(f\) 数组的值,便于后面进行答案统计。

统计答案是可以将每一个查询按 \(l\) 大小排序,将同个字母的位置从小到大压入队列中。

维护每个队列顶 \(\geqslant l\)。

每次通过 \(l\) 查询每个状态最近字母时,该字母堆顶就是答案。

维护堆总时间负载度 \(O(n)\),维护均摊 \(O(1)\),查询 \(O(1)\)。

统计答案时间复杂度 \(T(C^2_{26}n)\)。

但我们(也可能只有我)的空间复杂度较高,记录数组大小高达 \(2*10^5*325*2=1.3*10^8\)。

考虑进行优化,发现对于 \(r\) 而言,只关心 \(0/1\) 中的最大值,于是记录 \(r\) 端点的数组只需要记录最大值即可。

将 \(r\) 的记录数组与 \(l\) 的剥离开,减小了 \(\frac{1}{4}\) 的空间,由于基数大,于是多出了 \(4*10^7\) 的数组空间可以使用。

代码仅供参考:

#include<bits/stdc++.h>
using namespace std; #define F first
#define S second const int maxn=3*5e5+5,maxm=13*25+5,maxz=1e5+5; struct node
{
int l,r,id;
}t[maxz];
struct ANS
{
int val;
pair<char,char>c;
}Ans[maxz]; int m,n,cnt,ctl,ctr;
int f[maxm][2],gt[maxz][maxm],g[maxz][maxm][2],mp[2627],fpl[maxn],fpr[maxn];
//gt 为 r 的统计数组,g 为 l 的统计数组,mp 是 二元组的第一位*100+第二位 后得出的编号
bool vis[maxn];//记录该位置是不是左端点
bool cis[maxn];//记录该位置是不是右端点 pair<char,char>p[maxm];//编号对应的一组字母 char s[maxn]; queue<int>st[27]; bool cmp(node a,node b){return a.l<b.l;} inline int chs(char a,char b){return (a-'a'+1)*100+(b-'a'+1);} inline void ycl()//预处理二元组编号及编号对应二元组
{
for(char i='a';i<='z';i++)
{
for(char j=i+1;j<='z';j++)
{
if(j==i) continue;
p[++cnt]=make_pair(i,j);
mp[chs(i,j)]=cnt;
mp[chs(j,i)]=cnt;
}
}
} int main()
{
freopen("seq.in","r",stdin);
freopen("seq.out","w",stdout);
cin>>s+1;
n=strlen(s+1);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&t[i].l,&t[i].r);
t[i].id=i;
vis[t[i].l-1]=1;
cis[t[i].r]=1;
} sort(t+1,t+m+1,cmp); for(int i=1;i<=n;i++) st[s[i]-'a'+1].push(i);
for(int i=1;i<=26;i++) st[i].push(n+1);//队列优化统计 ycl();
for(int i=1;i<=n;i++)
{
for(int j='a';j<='z';j++)//转移
{
if(j==s[i]) continue;
pair<char,char>k=make_pair(s[i],j);
if(k.F>k.S) swap(k.F,k.S);
if(k.F==s[i]) f[mp[chs(k.F,k.S)]][0]=f[mp[chs(k.F,k.S)]][1]+1;
else f[mp[chs(k.F,k.S)]][1]=f[mp[chs(k.F,k.S)]][0]+1;
}
if(vis[i])//l 端点记录
{
ctl++;
fpl[i]=ctl;
for(int j=1;j<=cnt;j++) g[ctl][j][0]=f[j][0],g[ctl][j][1]=f[j][1];
}
if(cis[i])//r 端点记录
{
ctr++;
fpr[i]=ctr;
for(int j=1;j<=cnt;j++) gt[ctr][j]=max(f[j][0],f[j][1]);
}
}
for(int i=1;i<=m;i++)//求答案
{
pair<char,char>cans;
cans={0,0};
int ans=0;
for(int j=1;j<=cnt;j++)
{
pair<char,char>x=p[j];
while(st[x.F-'a'+1].front()<t[i].l) st[x.F-'a'+1].pop();//维护队列
while(st[x.S-'a'+1].front()<t[i].l) st[x.S-'a'+1].pop();
int fi=st[x.F-'a'+1].front();//最靠近 l 的字母
int se=st[x.S-'a'+1].front();
if(fi>t[i].r&&se>t[i].r) continue;
if(fi<se)
{
if(ans<gt[ fpr[t[i].r] ][j]-g[ fpl[t[i].l-1] ][j][1])
{
ans=gt[ fpr[t[i].r] ][j]-g[ fpl[t[i].l-1] ][j][1];
cans=x;
}
else if(ans==gt[ fpr[t[i].r] ][j]-g[ fpl[t[i].l-1] ][j][1])
{
if(cans>x) cans=x;
}
}
else if(fi>se)
{
swap(x.F,x.S);
if(ans<gt[ fpr[t[i].r] ][j]-g[ fpl[t[i].l-1] ][j][0])
{
ans=gt[ fpr[t[i].r] ][j]-g[ fpl[t[i].l-1] ][j][0];
cans=x;
}
else if(ans==gt[ fpr[t[i].r] ][j]-g[ fpl[t[i].l-1] ][j][0])
{
if(cans>x) cans=x;
}
}
}
Ans[t[i].id].val=ans;
Ans[t[i].id].c=cans;
}
for(int i=1;i<=m;i++) printf("%d %c%c\n",Ans[i].val,Ans[i].c.F,Ans[i].c.S);
}

2023NOIP A层联测10 T4 子序列的更多相关文章

  1. Java面试之持久层(10)

    91,什么是ORM?         对象关系映射(Object-Relational Mapping,简称ORM)是一种为了解决程序的面向对象模型与数据库的关系模型互不匹配问题的技术: 简单的说,O ...

  2. 如何从代码层防御10大安全威胁中的 Xpath Injection?

    普遍性和可检测性: Xpath 注入是 OWASP TOP10 安全威胁中 A1 Injection 中的一种,注入漏洞发生在应用程序将不可信的数据发送到解释器时.虽然注入漏洞很容易通过审查代码发现, ...

  3. 《细说PHP》第四版 样章 第18章 数据库抽象层PDO 10

    18.8  设计完美分页类 数据记录列表几乎出现在Web项目的每个模块中,假设一张表中有十几万条记录,我们不可能一次全都显示出来,当然也不能仅显示几十条.为了解决这样的矛盾,通常在读取时设置以分页的形 ...

  4. CSharpGL(12)用T4模板生成CSSL及其renderer代码

    CSharpGL(12)用T4模板生成CSSL及其renderer代码 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码中包含10多个独立 ...

  5. 使用T4模板生成代码的学习

    之前做项目使用的都是Db First,直接在项目中添加Entity Framework,使用T4模板(T4模板引擎之基础入门)生成DAL BLL层等(T4模板是一个同事给的,也没有仔细研究,代码如下: ...

  6. C# Winform 实现自定义半透明loading加载遮罩层

    在网页中通过div+css实现半透明效果不难,今天我们看看一种在winfrom中实现的方法: 效果图如下,正常时: 显示遮罩层时: 自定义遮罩层控件的源码如下: View Row Code 1 usi ...

  7. 用标准3层神经网络实现MNIST识别

    一.MINIST数据集下载 1.https://pjreddie.com/projects/mnist-in-csv/      此网站提供了mnist_train.csv和mnist_test.cs ...

  8. tensorFlow(四)浅层神经网络

    tensorFlow见基础 实验 MNIST数据集介绍 MNIST是一个手写阿拉伯数字的数据集. 其中包含有60000个已经标注了的训练集,还有10000个用于测试的测试集. 本次实验的任务就是通过手 ...

  9. 可变多隐层神经网络的python实现

    说明:这是我对网上代码的改写版本,目的是使它跟前一篇提到的使用方法尽量一致,用起来更直观些. 此神经网络有两个特点: 1.灵活性 非常灵活,隐藏层的数目是可以设置的,隐藏层的激活函数也是可以设置的 2 ...

  10. C# Winform 实现自定义半透明遮罩层介绍

    在网页中通过div+css实现半透明效果不难,今天我们看看一种在winfrom中实现的方法: 效果图如下,正常时: 显示遮罩层时: 自定义遮罩层控件的源码如下: View Row Code 1 usi ...

随机推荐

  1. 检测 NAT 类型

    使用 pystun3 pystun3 是一个用于获取 NAT 类型和外部 IP 的 Python STUN 客户端 安装: pip install pystun3 使用: pystun3 结果: NA ...

  2. 【测试平台开发】——01Vue前端框架实操

    一.VScode官网地址 https://code.visualstudio.com/ 但是官网下载贼慢,需要修改下国内地址: 原地址:https://az764295.vo.msecnd.net/s ...

  3. rabbitmq高可用集群搭建

    需求分析基本情况 在进行RabbitMQ搭建时,我们基于现有的连接数据和业务需求进行了深入分析.目前的统计数据显示,连接数为631,队列数为80418.为了确保业务需求的顺利满足,我们需要在云产品和自 ...

  4. 使用 Helm 在 Kubernetes 上安装 Consul

    Consul Sync 部署 官方文档部署:https://developer.hashicorp.com/consul/docs/k8s/installation/install 部署版本 1.14 ...

  5. Go runtime 调度器精讲(二):调度器初始化

    原创文章,欢迎转载,转载请注明出处,谢谢. 0. 前言 上一讲 介绍了 Go 程序初始化的过程,这一讲继续往下看,进入调度器的初始化过程. 接着上一讲的执行过程,省略一些不相关的代码,执行到 runt ...

  6. 深度学习模型训练的过程理解(训练集、验证集、测试集、batch、iteration、epoch、单步预测、多步预测、kernels、学习率)

    呜呜呜呜,感谢大佬学弟给我讲干货. 本来是讨论项目的,后面就跑偏讲论文模型了. 解答了我一直以来的疑问: 数据放模型里训练的过程. 假设我们有一个数据集26304条数据,假设设置模型读入1000条,如 ...

  7. OpenSSL证书通过Subject Alternative Name扩展字段扩展证书支持的域名

    1.概述 1.1 什么是Subject Alternative Name(证书主体别名) SAN(Subject Alternative Name) 是 SSL 标准 x509 中定义的一个扩展.它允 ...

  8. Maven高级——依赖管理

    依赖管理 依赖指向当前项目运行所需的jar包,一个项目可以设置多个依赖 依赖传递 依赖具有传递性 直接依赖:在当前项目中通过依赖配置建立的依赖关系 间接依赖:被依赖的资源如果依赖其他资源.当前项目间接 ...

  9. 浅谈数栈产品里的 Descriptions 组件

    我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值. 本文作者:修能 What's? 数栈产品里的 Description ...

  10. JSP+Java编程资源

    <JSP+Servlet+Tomcat应用开发从零开始学(第2版)>源码课件视频下载地址: https://pan.baidu.com/s/1HkFRul3wYBxe-skXCoQPwg ...