8/13 最短路+DP+倍增lca+基础思维
Posted 钟钟终
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了8/13 最短路+DP+倍增lca+基础思维相关的知识,希望对你有一定的参考价值。
Word 小白月赛D
题意:将一个单词s转化为单词t,每次只改变一个单词,且变化的单词必须在给定单词表内
思路:
1.单词s看作是起点,单词t看作是终点。
2.每次变化一个单词,说明两个字符串若只有一个单词差异则可以变化,需要连线。
2.此时便看出是最短路,但是由于n属于1~2000,我不死心的试了以下floyed算法,可惜超时了。。。
floyed的O(n^3)做法+打印路径:
#include<bits/stdc++.h>
#define endl '\\n'
#define re register
#define int long long
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=2e3+10;
const int inf=0x3f3f3f3f;
const int mod=1e7+7;
int n,m,f[2005][2005],p[2005][2005];
string str[N];
bool check(int i,int j)
int res=0;
string s1=str[i],s2=str[j];
for(int g=0;g<m;g++)
if(s1[g]!=s2[g])
res++;
return res==1;
void path(int i,int j)
if(p[i][j]==0) return;
int k=p[i][j];
path(i,k);
cout<<str[k]<<endl;
path(k,j);
void solve()
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>str[i];
string s,t;cin>>s>>t;
if(s==t)
cout<<0<<endl<<s<<endl<<t<<endl;
return;
int d1=0,d2=0;
for(int i=1;i<=n;i++)
if(str[i]==s) d1=i;
if(str[i]==t) d2=i;
if(!d1) str[++n]=s,d1=n;
if(!d2) str[++n]=t,d2=n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]=inf;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(check(i,j))
f[i][j]=f[j][i]=1;
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(f[i][j]>f[i][k]+f[k][j])
f[i][j]=f[i][k]+f[k][j];
p[i][j]=k;
if(f[d1][d2]==inf)
cout<<-1<<endl;return;
cout<<f[d1][d2]-1<<endl;
cout<<s<<endl;
path(d1,d2);
cout<<t<<endl;
signed main()
solve();
return 0;
Dijkstra的堆优化:
#include<bits/stdc++.h>
#define endl '\\n'
#define re register
#define int long long
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=2e5+10;
const int inf=0x3f3f3f3f;
const int mod=1e7+7;
int n,m,d1,d2,dis[2005],pre[2005],vis[2005];
string str[2005];
vector<int>e[N];
priority_queue<pair<int,int>>q;
bool check(int i,int j)
int res=0;
string s1=str[i],s2=str[j];
for(int g=0;g<m;g++)
if(s1[g]!=s2[g])
res++;
return res==1;
void path(int u)
if(u==d1)
cout<<str[u]<<endl;return;
path(pre[u]);
cout<<str[u]<<endl;
void dijkstra(int s)
for(int i=0;i<=n;i++)
dis[i]=inf;
dis[s]=0;
q.push(0,s);
while(q.size())
auto t=q.top();q.pop();
int u=t.second;
if(vis[u])
continue;
vis[u]=1;
for(int ed:e[u])
int v=ed;
if(dis[v]>dis[u]+1)
dis[v]=dis[u]+1;
pre[v]=u;
q.push(-dis[v],v);
void solve()
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>str[i];
string s,t;cin>>s>>t;
if(s==t)
cout<<0<<endl<<s<<endl<<t<<endl;
return;
for(int i=1;i<=n;i++)
if(str[i]==s) d1=i;
if(str[i]==t) d2=i;
if(!d1) str[++n]=s,d1=n;
if(!d2) str[++n]=t,d2=n;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(check(i,j))
e[i].push_back(j);
e[j].push_back(i);
dijkstra(d1);
if(dis[d2]==inf)
cout<<-1<<endl;return;
cout<<dis[d2]-1<<endl;
path(d2);
signed main()
solve();
return 0;
Slash 小白月赛E
看完讲解视频,才稍微有点懂了。
很多是无效状态,即使有数字表示,也无任何意义,关注点应放在有意义的状态是否能正确转移。
思路:
1.dp[i][j][k]
表示以i行j列结尾的字符串表示s的前k位中,包含了多少字符串s的个数。
2.规定匹配字符串s时第0个字符为记录更新后长度
3.对于没有匹配成功的状态转移:f[i][j][0]=max(f[i][j][0],f[i-1][j][k],f[i][j-1][k])
#include<bits/stdc++.h>
#define endl '\\n'
#define re register
#define int long long
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=2e5+10;
const int inf=0x3f3f3f3f;
const int mod=7e6+7;
int n,m,f[105][105][105];
char s[105],c[105][105];
void solve()
cin>>n>>m;
scanf("%s",s+1);
int len=strlen(s+1);
for(int i=1;i<=n;i++)
scanf("%s",&c[i][1]);
for(int i=0;i<=n;i++)for(int j=0;j<=m;j++)for(int k=0;k<=n;k++)
f[i][j][k]=-inf;
//预处理
f[0][1][0]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=1;k<=len;k++)
//匹配
if(c[i][j]==s[k])
f[i][j][k]=max(f[i-1][j][k-1],f[i][j-1][k-1]);
//规定第0个字符为更新后长度
f[i][j][0]=f[i][j][len]+1;
//匹配未成功
for(int k=0;k<=n;k++)
f[i][j][0]=max(f[i][j][0],f[i-1][j][k],f[i][j-1][k]);
int ans=0;
for(int i=0;i<=len;i++)
ans=max(ans,f[n][m][i]);
cout<<ans<<endl;
signed main()
solve();
return 0;
G. Path Prefixes
思路:
1.倍增lca,这里不需要差分,直接记录自根节点开始到相应节点的总和sum
2.计算差值,开一个数组g[u][j]
表示u点向上跳2^j到响应祖先,所需要减去的w2的和
#include<bits/stdc++.h>
#define endl '\\n'
#define re register
#define int long long
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=2e5+10;
const int inf=0x3f3f3f3f;
const int mod=7e6+7;
int n,w1[N],w2[N],sum1[N],sum2[N];
int dep[N]; //存u点的深度
int fa[N][20]; //存从u点向上跳2^i层的祖先节点
int g[N][20];
vector<int>e[N];
void dfs(int u,int pare)
dep[u]=dep[pare]+1;
sum1[u]=sum1[pare]+w1[u];
sum2[u]=sum2[pare]+w2[u];
fa[u][0]=pare;
g[u][0]=w2[u];
for(int i=1;i<=19;i++)
fa[u][i]=fa[fa[u][i-1]][i-1]以上是关于8/13 最短路+DP+倍增lca+基础思维的主要内容,如果未能解决你的问题,请参考以下文章