Codeforces Round #605 (Div. 3)(E、F


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;
}

发布了457 篇原创文章 · 获赞 37 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/105227481