Atcoder ABC329E Stamp 题解 [ 绿 ] [ 线性 dp ]
Stamp:难点主要在 dp 转移的细节与分讨上,但通过改变状态设计可以大大简化分讨细节的题。
观察
首先要有一个观察:只要某一个前缀能被覆盖出来,那么无论它后面多出来多少,后面的字符串都可以帮他重新覆盖回去。这也就是 dp 为啥没有后效性的原因。
除此之外,还要注意一个字符串不仅能在其他字符串上面,还能被盖在最下层来达到用子串接着覆盖的效果。
暴力 dp 思路
设
更巧妙的 dp 思路
设
那么接下来分为三个情况,这三种情况的前提条件就是
,也就是当前 刚开始匹配。也就是说前面的部分只要能被覆盖出就行了,不管他前面匹配到多少个,则 。- 这个字符接着上一个字符覆盖,则
。 - 这个字符被盖在最下面,用自己的后缀覆盖。这种情况需要满足的条件是前一个字符串一定要先被覆盖完,才可以在下一个字符串覆盖前覆盖在它的下面。则
。
直接这样转移复杂度也是
代码
#include <bits/stdc++.h>
#define fi first
#define se second
#define lc (p<<1)
#define rc ((p<<1)|1)
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi=pair<int,int>;
bool dp[200005][10],hv[200005];
int n,m;
char a[200005],b[10];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>a+1>>b+1;
dp[0][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i]==b[j])
{
dp[i][j]|=dp[i-1][j-1];
dp[i][j]|=dp[i-1][m];
if(j==1)dp[i][j]|=hv[i-1];
}
hv[i]|=dp[i][j];
}
}
if(dp[n][m])cout<<"Yes";
else cout<<"No";
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战