Educational Codeforces Round 131 E,F
E
一道DP题。
首先发现我们有最优解的策略:一定是在后面删掉一些数(用left和delete),然后用(home)到开头,再从前面删掉一些数(用right和delete)。
那么我们可以设表示我们使用中前个字符,最后成为的前个字符,并且光标最后在字符之后。
有转移:
同理设表示我们使用中后个字符,最后成为的后个字符,并且光标最后在字符之前。
也有转移:
注意我们从前往后要想删掉一个字符,必须先按right,然后再按下delete,但是从后往前删的时候,只要按delete就可以了(因为delete相当于按了后自动往左走),这也是为什么的第二个转移要加二,而的第二个转移只要加。
那么答案就是:
这样是的,过不了。
那么考虑在转移完成后,设表示光标不动,的前个字符匹配的前个字符,有转移:
对于同理。
这样,我们的答案就为:
时间复杂度就降为。(相当于做了前缀和后缀min)
注意直接开四个数组,会MLE,那么我们可以利用原来的储存,原来的储存,这样就只要开两个数组即可。
#include<bits/stdc++.h>
#define debug(...) std::cerr<<#__VA_ARGS__<<" : "<<__VA_ARGS__<<std::endl
const int INF=1000000000;
int n,m;
char a[5005],b[5005];
int f[5005][5005],g[5005][5005];
void solve() {
scanf("%d%d",&n,&m);
scanf("%s%s",a+1,b+1);
for(int i=0;i<n+5;i++) {
for(int j=0;j<m+5;j++) {
f[i][j]=g[i][j]=INF;
}
}
f[0][0]=0;
for(int i=1;i<=n;i++) {
for(int j=0;j<=i;j++) {
f[i][j]=std::min(f[i][j],f[i-1][j]+2);
if(j&&a[i]==b[j]) {
f[i][j]=std::min(f[i][j],f[i-1][j-1]+1);
}
}
}
g[n+1][m+1]=0;
for(int i=n;i>=1;i--) {
for(int j=m+1;m-j<=n-i;j--) {
g[i][j]=std::min(g[i][j],g[i+1][j]+1);
if(j!=m+1&&a[i]==b[j]) {
g[i][j]=std::min(g[i][j],g[i+1][j+1]+1);
}
}
}
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(a[i]==b[j]) {
f[i][j]=std::min(f[i][j],f[i-1][j-1]);
}
}
}
for(int i=n;i>=1;i--) {
for(int j=m;j>=1;j--) {
if(a[i]==b[j]) {
g[i][j]=std::min(g[i][j],g[i+1][j+1]);
}
}
}
int ans=std::min(f[n][m]+1,g[1][1]);
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
ans=std::min(ans,f[i][j]+g[i+1][j+1]+1);
}
}
if(ans==INF) printf("-1\n");
else printf("%d\n",ans);
return;
}
int main() {
int T; scanf("%d",&T);
while(T--) solve();
return 0;
}
F
好像有别的做法,这里我取题解的做法因为我不会。
就是首先我们想如何的做这题。考虑对于询问,我们枚举。假设目前区间内共有个点,那么合法的有个。
那么考虑优化,发现我们其实就是要维护。相当于进行如下操作:
- 对某一段区间的加或减。
- 求。
发现。
那么我们就相当于要维护和。
这可以用矩阵实现。我们设矩阵。
区间加一:由于,故可以看成一个矩阵乘法:
区间减一也是相似的:
至此,我们就是要进行矩阵区间乘法和矩阵区间和,这可以使用线段树解决这个问题。
注意有可能有些点目前没有加入,所以我们不能以它作为,这个可以使用一个表示区间是否有加入其中的点。在update时,如果左或右儿子的,我们才进行转移。
在加入或删除一个点时,我们也相应用线段树单点修改更新。
时间复杂度为,为矩阵大小。
我之前用了vector储存矩阵,结果在2e5的数据上运行300多秒都没出结果,换成指针数组才用了3.8秒。
#include<bits/stdc++.h>
#define debug(...) std::cerr<<#__VA_ARGS__<<" : "<<__VA_ARGS__<<std::endl
using ll=long long;
ll unit[3][3]={{1,0,0},{0,1,0},{0,0,1}};
ll del[3][3]={{1,-1,1},{0,1,-2},{0,0,1}};
ll add[3][3]={{1,1,1},{0,1,2},{0,0,1}};
ll val[800005][1][3],lazy[800005][3][3];
bool flag[800005];
void plus(ll (*a1)[3],ll (*a2)[3]) {
for(int i=0;i<3;i++) a1[0][i]+=a2[0][i];
}
void mul1(ll (*a1)[3],ll (*a2)[3]) {
ll pre[3]={a1[0][0],a1[0][1],a1[0][2]};
a1[0][0]=a1[0][1]=a1[0][2]=0;
for(int i=0;i<3;i++) for(int j=0;j<3;j++) a1[0][i]+=pre[j]*a2[j][i];
}
void mul2(ll (*a1)[3],ll (*a2)[3]) {
ll pre[3][3]={{a1[0][0],a1[0][1],a1[0][2]},{a1[1][0],a1[1][1],a1[1][2]},{a1[2][0],a1[2][1],a1[2][2]}};
a1[0][0]=0; a1[0][1]=0; a1[0][2]=0; a1[1][0]=0; a1[1][1]=0; a1[1][2]=0; a1[2][0]=0; a1[2][1]=0; a1[2][2]=0;
for(int i=0;i<3;i++) for(int j=0;j<3;j++) for(int k=0;k<3;k++) a1[j][k]+=pre[j][i]*a2[i][k];
}
void push(int pos) {
mul1(val[pos<<1],lazy[pos]);
mul1(val[pos<<1|1],lazy[pos]);
mul2(lazy[pos<<1],lazy[pos]);
mul2(lazy[pos<<1|1],lazy[pos]);
for(int i=0;i<3;i++) for(int j=0;j<3;j++) lazy[pos][i][j]=unit[i][j];
}
void upd(int pos) {
val[pos][0][0]=val[pos][0][1]=val[pos][0][2]=0;
if(flag[pos<<1]) plus(val[pos],val[pos<<1]);
if(flag[pos<<1|1]) plus(val[pos],val[pos<<1|1]);
flag[pos]=flag[pos<<1]|flag[pos<<1|1];
}
void SetMatrix(int l,int r,ll (*mt)[3],int pos,int lef,int rig) {
if(l<=lef&&rig<=r) {
mul2(lazy[pos],mt); mul1(val[pos],mt);
} else if(l<=rig&&r>=lef) {
int mid=lef+rig>>1;
push(pos);
SetMatrix(l,r,mt,pos<<1,lef,mid);
SetMatrix(l,r,mt,pos<<1|1,mid+1,rig);
upd(pos);
}
}
void SetNode(int p,int f,int pos,int lef,int rig) {
if(lef==rig) {flag[pos]=f; return;}
push(pos);
int mid=lef+rig>>1;
if(p<=mid) SetNode(p,f,pos<<1,lef,mid);
else SetNode(p,f,pos<<1|1,mid+1,rig);
upd(pos);
}
void build(int pos,int lef,int rig) {
for(int i=0;i<3;i++) for(int j=0;j<3;j++) lazy[pos][i][j]=unit[i][j];
if(lef==rig) {
val[pos][0][0]=1;
return;
}
int mid=lef+rig>>1;
build(pos<<1,lef,mid);
build(pos<<1|1,mid+1,rig);
upd(pos);
}
int d,in[200005];
int main() {
int q; scanf("%d%d",&q,&d);
build(1,1,200000);
for(int i=1;i<=q;i++) {
int x; scanf("%d",&x);
if(in[x]) {
in[x]=0; SetNode(x,0,1,1,200000);
int l=std::max(1,x-d),r=x-1;
if(l<=r) SetMatrix(l,r,del,1,1,200000);
} else {
in[x]=1; SetNode(x,1,1,1,200000);
int l=std::max(1,x-d),r=x-1;
if(l<=r) SetMatrix(l,r,add,1,1,200000);
}
printf("%lld\n",(val[1][0][2]-val[1][0][1])/2);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话