E.Nearest Opposite Parity
题意:
给长度为n的数组a
a(i)表示i位置可以走到i+a(i)或者i-a(i),前提是要走到的位置合法(在1到n之间)
现在问每个位置a(i)走到a(j),其中a(i)与a(j)奇偶性不同,最少步数是多少
解法:
建立两个奇偶性不同的超级点,奇点连接所有奇数点,偶点连接所有偶数点,
那么问题就变成了每个点到达奇偶性不同的超级点的最短路。
如果对于每个点都计算一遍,是多源最短路,需要多次计算。
一个好的解决方法是建立反向边,从超级点开始跑,这样就变成了单源最短路了。
ps:因为边权为1,因此也可以bfs
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=1e6+5;
int head[maxm],nt[maxm],to[maxm],w[maxm],cnt;
int mark[maxm],d[maxm];
int ans[maxm];
int a[maxm];
int n;
void add(int x,int y){
cnt++;nt[cnt]=head[x];head[x]=cnt;to[cnt]=y;
}
void spfa(int st){
queue<int>q;
q.push(st);
for(int i=1;i<=n;i++)mark[i]=0,d[i]=1e9;
mark[st]=1;d[st]=0;
while(!q.empty()){
int x=q.front();
q.pop();
mark[x]=0;
for(int i=head[x];i;i=nt[i]){
int v=to[i];
if(d[v]>d[x]+1){
d[v]=d[x]+1;
if(!mark[v]){
mark[v]=1;
q.push(v);
}
}
}
}
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
if(a[i]&1)add(n+1,i);//n+1是奇超级点
else add(0,i);//0是偶超级点
}
for(int i=1;i<=n;i++){//反向边
if(i-a[i]>=1)add(i-a[i],i);
if(i+a[i]<=n)add(i+a[i],i);
}
spfa(0);
for(int i=1;i<=n;i++){
if(a[i]&1)ans[i]=d[i]-1;//奇点到偶超级点的最短路
}
spfa(n+1);
for(int i=1;i<=n;i++){
if(a[i]%2==0)ans[i]=d[i]-1;//偶点到奇超级点的最短路
}
for(int i=1;i<=n;i++){
if(ans[i]==1e9-1)ans[i]=-1;
cout<<ans[i]<<' ';
}
return 0;
}
F. Two Bracket Sequences
题意:
给两个括号串,要求构造一个最短的括号串,
满足给定的两个串是构造出的串的子序列,且构造出的串本身是一个合法的括号序列(即左右括号可匹配)
输出构造出的串
解法:
一个合法的括号序列,令左括号'('为1,右括号')'为-1,那么这个序列的前缀和一定是大于等于0的,且最后和为0
设d[i][j][k]表示s串匹配到第i为,t串匹配到第j位,序列的前缀和为k的最少步数
因为需要串合法,因此k>=0,又因为s串和t串的长度不超过200,200对"()"一定能满足要求,则k<=200
因为需要最少步数,所以可以利用最短路转移,发现每次操作数都只加1,那么用bfs就够了
因为题目要求输出方案,所以转移的时候需要记录一下路径
code:
#include<bits/stdc++.h>
using namespace std;
const int N=205;
struct Node{
int a,b,c;
}pre[N][N][N<<1];//记录dp路径
char c[N][N][N<<1];
int d[N][N][N<<1];
char s[N],t[N];
int n,m;
void bfs(){
memset(d,-1,sizeof d);
d[0][0][0]=0;
queue<Node>q;
q.push({0,0,0});
Node p;
while(!q.empty()){
Node x=q.front();q.pop();
//加左括号
p.a=x.a+(x.a+1<=n&&s[x.a+1]=='(');
p.b=x.b+(x.b+1<=m&&t[x.b+1]=='(');
p.c=x.c+1;
if(p.c<=200&&d[p.a][p.b][p.c]==-1){
d[p.a][p.b][p.c]=d[x.a][x.b][x.c]+1;
pre[p.a][p.b][p.c]=x;//记录路径
c[p.a][p.b][p.c]='(';
q.push(p);
}
//加右括号
p.a=x.a+(x.a+1<=n&&s[x.a+1]==')');
p.b=x.b+(x.b+1<=m&&t[x.b+1]==')');
p.c=x.c-1;
if(p.c>=0&&d[p.a][p.b][p.c]==-1){
d[p.a][p.b][p.c]=d[x.a][x.b][x.c]+1;
pre[p.a][p.b][p.c]=x;//记录路径
c[p.a][p.b][p.c]=')';
q.push(p);
}
}
}
void dfs(Node x){
if(x.a+x.b+x.c==0)return ;
dfs(pre[x.a][x.b][x.c]);
putchar(c[x.a][x.b][x.c]);
}
signed main(){
scanf("%s",s+1);
scanf("%s",t+1);
n=strlen(s+1);
m=strlen(t+1);
bfs();
dfs(pre[n][m][0]);
putchar(c[n][m][0]);
return 0;
}