CEOI2013部分题解

前言

scy说要我和FYC去负责一套CEOI
然后我被分到CEOI2013
然后要有题解和中文翻译还有标程QAQ
现在我只水了三题。。
水了两天,在这里感谢LHY对我英语上的巨大帮助
题面什么的我已经翻译好了,在caioj,但是题目似乎并不会这么快放出来

现在这里存一下题解吧

D1T2 TRAM

这题是我自己yy的做法,不知道标解是什么,但反正能过,不喜欢我的可以自己去看英文题解

这道题我们不难想到一个最短距离肯定是在两行中间的人
如果行数之差为奇数就处理一行,反之两行
其实如果你分类讨论是可以处理少一点的,但是多一点你也不会T对吧
然后呢,你就可以维护一个链表,表示哪些行上边有人
删除和加入就暴力弄就好了,反正是链表
然后每次枚举相邻的两个行,看看他们中间的到他们最优距离是多少
然后如果是1的话,说明还可以在同一行,列数不同,然后你就再扫一次,看看有没有解
然后还有一种特殊的地方就是第一行和最后一行
这个复杂度是O(m*n)的,期望得分70分
代码我写了,如果觉得理解不好可以看一看
由于细节什么的蛮多,于是我写了 一早上+一晚上

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
const int MAX=1<<30;
const int N=150005;
const int M=150005;
int n,m;
struct qq
{
    int next,last; 
    int c[2];//第一行是哪一个客人   第二行是哪一个客人
    qq ()
    {
        next=last=0;
        c[0]=c[1]=-1;
    };
}s[N];//我的链表只储存每一行连接的
int cnt=0;//现在有多少行有人 
int a[M],tot=0;
void print (int x)//输出这个人 
{
    int now=a[x];
    if (s[now].c[0]==x) printf("%d %d\n",now,1);
    else             printf("%d %d\n",now,2);
}
int get_dis (int x1,int y1,int x2,int y2)   {return (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1);}
void Ins (int x,int A,int B)//插在第x行后面    位置时(a,b)
{
//  printf("HA:%d %d %d %d\n",x,A,B,tot);
    s[A].c[B]=tot;
    if (s[A].c[B^1]!=-1)//这一行之前有人
        return ;
    cnt++;
    s[A].last=x;
    s[A].next=s[x].next;
    s[s[x].next].last=A;
    s[x].next=A;
}
void Del (int A,int B)//这个人离开了
{
    s[A].c[B]=-1;
    if (s[A].c[B^1]!=-1)//这一行是两个人的
        return ;
    cnt--;
    int Last=s[A].last,Next=s[A].next;
    s[Last].next=Next;s[Next].last=Last;
}
int aa,bb,ans;//坐标
void update (int xx,int yy,int zz)
{
    //printf("NO:%d %d %d\n",xx,yy,zz);
    if (zz>ans)
    {
        ans=zz;aa=xx;bb=yy;
        return ;
    }
    if (zz==ans&&xx<aa)
    {
        ans=zz;aa=xx;bb=yy;
        return ;
    }
    if (zz==ans&&xx==aa&&yy<bb)
    {
        ans=zz;aa=xx;bb=yy;
        return ;
    }
    return ;
}
void compare (int x,int y,int A)//这两行中间   比较这一行两个点的最优值 
{                      

    int d0=MAX,d1=MAX;
    if (x!=0&&s[x].c[0]!=-1) d0=min(d0,get_dis(x,0,A,0));
    if (x!=0&&s[x].c[1]!=-1) d0=min(d0,get_dis(x,1,A,0));
    if (y!=n+1&&s[y].c[0]!=-1) d0=min(d0,get_dis(y,0,A,0));
    if (y!=n+1&&s[y].c[1]!=-1) d0=min(d0,get_dis(y,1,A,0));


    if (x!=0&&s[x].c[1]!=-1) d1=min(d1,get_dis(x,1,A,1));
    if (x!=0&&s[x].c[0]!=-1) d1=min(d1,get_dis(x,0,A,1));
    if (y!=n+1&&s[y].c[1]!=-1) d1=min(d1,get_dis(y,1,A,1));
    if (y!=n+1&&s[y].c[0]!=-1) d1=min(d1,get_dis(y,0,A,1));
    update(A,0,d0);update(A,1,d1);
    return ;
}
int main()
{
    scanf("%d%d",&n,&m);
    s[0].last=-1;s[0].next=n+1;
    s[n+1].last=0;s[n+1].next=n+2;
    while (m--)
    {   
        char ss[5];
        scanf("%s",ss);

        if (ss[0]=='E')//来了一个人 
        {
            if (cnt==n)//如果每一行起码有一个人
            {
                for (int u=1;u<=n;u++)
                {
                    if (s[u].c[0]==-1) {a[++tot]=u;Ins(u-1,u,0);break;}
                    if (s[u].c[1]==-1) {a[++tot]=u;Ins(u-1,u,1);break;}
                }
            }
            else if (cnt==0)//现在一个人也没有
            {
                a[++tot]=1;
                Ins(0,1,0);
            }
            else//有人,但不满 
            {
                ans=0;
                aa=MAX;bb=MAX;
                if (s[0].next!=1)//第一行没有人
                    compare(0,s[0].next,1);//在哪个比较优
                if (s[n+1].last!=n)//最后一行没有人
                    compare(s[n+1].last,n+1,n);

                for (int u=s[0].next;u!=s[n+1].last;u=s[u].next)
                {
                    int l=u,r=s[l].next;
                    if ((r-l)%2==0)//奇数
                        compare(l,r,(l+r)>>1);
                    else
                    {
                        compare(l,r,(l+r)>>1);
                        compare(l,r,(l+r+1)>>1);
                    }
                }
            //  printf("ooo:%d %d %d\n",aa,bb,ans);
                if (ans<=1)
                {
                    for (int u=s[0].next;u!=n+1;u=s[u].next)
                    {
                        if (aa<=u) break;
                        if (s[u].c[0]==-1)//这个位置时空的
                        {
                            aa=u;bb=0;
                            break;
                        }
                        if (s[u].c[1]==-1)//这个位置时空的
                        {
                            aa=u;bb=1;
                            break;
                        }
                    }
                }
            //  printf("K:%d %d\n",aa,bb);
                a[++tot]=aa;
                for (int u=0;u!=n+1;u=s[u].next)
                {
                    int l=u,r=s[l].next;
                    //printf("FYC:%d %d\n",l,r);
                    if (l<=aa&&r>=aa)
                    {
                        //printf("OZY:%d %d %d\n",l,aa,bb);
                        Ins(l,aa,bb);
                        break;
                    }
                }
            }
            print(tot);
        }
        else//走了一个人 
        {
            tot++;
            int x;
            scanf("%d",&x);
            int now=a[x];
            if (s[now].c[0]==x) Del(now,0);
            else Del(now,1);
        }
    //  printf("YES:%d\n",cnt);
        /*for (int u=0;u<=n+1;u++)
            printf("%d:%d %d\n",u,s[u].c[0],s[u].c[1]);*/
    }
    return 0;
}

我们考虑对上面的算法进行优化,就是说每一次扫太慢了,因为有很多信息是不会变的,可以用之前的结果来代替这个龟速的枚举
那么我们就想,有什么东西可以支持修改和查询最小值呢?
没错,就是set
我们就维护一个set表示两行之间的答案就可以了
然后插入和删除就暴力重构一下有变化的地方,再把它丢进去就好了。。
感觉蛮简单的。。大家应该都能懂吧

#include<cstdio>
#include<queue>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<set>
using namespace std;
typedef long long LL;
const LL MAX=1LL<<55;
const int N=150005;
const int M=150005;
int n,m;
struct qq
{
    int next,last; 
    int c[2];//第一行是哪一个客人   第二行是哪一个客人
    qq ()
    {
        next=last=0;
        c[0]=c[1]=-1;
    };
}s[N];//我的链表只储存每一行连接的
int cnt=0;//现在有多少行有人 
int a[M],tot=0;
set<int> S; //当前至少有一个位置是空的地方
set<int>::iterator it;
set<pair<LL,int> > SS;//最优解
set<pair<LL,int> >::iterator It;
struct qt
{
    int a,b;
    LL ans;//两个坐标   ans 
}g[N];//如果这个点存在的话,就更新这三个东西 
void print (int x)//输出这个人
{
    int now=a[x];
    if (s[now].c[0]==x) printf("%d %d\n",now,1);
    else             printf("%d %d\n",now,2);
}
LL get_dis (int x1,int y1,int x2,int y2)   {return (LL)(x2-x1)*(x2-x1)+(LL)(y2-y1)*(y2-y1);}
int aa,bb,ans_l;
LL ans;//坐标
void update (int xx,int yy,LL zz,int l)
{
    #define hehe1 {ans=zz;aa=xx;bb=yy;ans_l=l;}
    if (zz>ans)
        hehe1;
    if (zz==ans&&xx<aa)
        hehe1;
    if (zz==ans&&xx==aa&&yy<bb)
        hehe1;
    return ;
}
void update1 (int a,int b,LL Dis,int x)
{
    //printf("OZY:%d %d %d %d %d\n",a,b,Dis,x,g[x].ans);
    #define hehe g[x]=(qt){a,b,Dis}; 
    if (Dis>g[x].ans)
        hehe;
    if (Dis==g[x].ans&&a<g[x].a)
        hehe;
    if (Dis==g[x].ans&&a==g[x].a&&b<g[x].b)
        hehe;
    //printf("FYC:%d %d %d %d %d\n",a,b,Dis,x,g[x].ans);
    return ;
}
void compare (int x,int y,int A)//算出这两行里面,最优值
{                      
    if (A<=x||A>=y) return ;
    LL d0=MAX,d1=MAX;
    if (x!=0&&s[x].c[0]!=-1) d0=min(d0,get_dis(x,0,A,0));
    if (x!=0&&s[x].c[1]!=-1) d0=min(d0,get_dis(x,1,A,0));
    if (y!=n+1&&s[y].c[0]!=-1) d0=min(d0,get_dis(y,0,A,0));
    if (y!=n+1&&s[y].c[1]!=-1) d0=min(d0,get_dis(y,1,A,0));


    if (x!=0&&s[x].c[1]!=-1) d1=min(d1,get_dis(x,1,A,1));
    if (x!=0&&s[x].c[0]!=-1) d1=min(d1,get_dis(x,0,A,1));
    if (y!=n+1&&s[y].c[1]!=-1) d1=min(d1,get_dis(y,1,A,1));
    if (y!=n+1&&s[y].c[0]!=-1) d1=min(d1,get_dis(y,0,A,1));

    if (d0!=MAX) update1(A,0,d0,x);
    if (d1!=MAX) update1(A,1,d1,x);
    return ;
}
void K (int u)//重构这个 
{
    if (u==0||u>=n) return ;
    if (SS.count(make_pair(-g[u].ans,u))>0) 
        SS.erase(make_pair(-g[u].ans,u));

    g[u].ans=-1;g[u].a=g[u].b=MAX;
    int l=u,r=s[l].next;
    if ((r-l)%2==0)//奇数
        compare(l,r,(l+r)>>1);
    else
    {
        compare(l,r,(l+r)>>1);
        compare(l,r,(l+r+1)>>1);
    }
    SS.insert(make_pair(-g[u].ans,u));
}
void Ins (int x,int A,int B)//插在第x行后面    位置时(a,b)
{
    s[A].c[B]=tot;
    if (s[A].c[B^1]!=-1)//这一行之前有人
    {
        K(x);K(A);
        S.erase(A);
        return ;
    }
    cnt++;
    s[A].last=x;
    s[A].next=s[x].next;
    s[s[x].next].last=A;
    s[x].next=A;

    K(x);K(A);
}
void Del (int A,int B)//这个人离开了
{
    s[A].c[B]=-1;
    S.insert(A);
    if (s[A].c[B^1]!=-1)//这一行是两个人的
    {
        K(s[A].last);K(A);
        return ;
    }
    SS.erase(make_pair(-g[A].ans,A));g[A].ans=-1;g[A].a=g[A].b=MAX;
    cnt--;
    int Last=s[A].last,Next=s[A].next;
    s[Last].next=Next;s[Next].last=Last;
    K(Last);
}
int main()
{
    /*freopen("tram.in.8a","r",stdin);
    freopen("a.out","w",stdout);*/
    scanf("%d%d",&n,&m);
    for (int u=1;u<=n;u++)  S.insert(u);
    s[0].last=-1;s[0].next=n+1;
    s[n+1].last=0;s[n+1].next=n+2;
    while (m--)
    {   
        char ss[5];
        scanf("%s",ss);

        if (ss[0]=='E')//来了一个人 
        {
            if (cnt==n)//如果每一行起码有一个人
            {
                it=S.begin();
                if (it!=S.end())
                {
                    int u=(*it);
                    if (s[u].c[0]==-1) {a[++tot]=u;Ins(u-1,u,0);}
                    if (s[u].c[1]==-1) {a[++tot]=u;Ins(u-1,u,1);}
                }
            }
            else if (cnt==0)//现在一个人也没有
            {
                a[++tot]=1;
                Ins(0,1,0);
            }
            else//有人,但不满 
            {
                ans=0;
                aa=MAX;bb=MAX;
                if (s[0].next!=1)//第一行没有人
                {
                    int now=s[0].next;
                    LL d=MAX;
                    if (s[now].c[0]!=-1) d=min(d,get_dis(1,0,now,0));
                    if (s[now].c[1]!=-1) d=min(d,get_dis(1,0,now,1));
                    update(1,0,d,0);

                    d=MAX;
                    if (s[now].c[0]!=-1) d=min(d,get_dis(1,1,now,0));
                    if (s[now].c[1]!=-1) d=min(d,get_dis(1,1,now,1));
                    update(1,1,d,0);
                }
                if (s[n+1].last!=n)//最后一行没有人
                {
                    int now=s[n+1].last;
                    LL d=MAX;
                    if (s[now].c[0]!=-1) d=min(d,get_dis(n,0,now,0));
                    if (s[now].c[1]!=-1) d=min(d,get_dis(n,0,now,1));
                    update(n,0,d,now);

                    d=MAX;
                    if (s[now].c[0]!=-1) d=min(d,get_dis(n,1,now,0));
                    if (s[now].c[1]!=-1) d=min(d,get_dis(n,1,now,1));
                    update(n,1,d,now);
                }

                /*for (int u=s[0].next;u!=s[n+1].last;u=s[u].next)
                {
                    update(g[u].a,g[u].b,g[u].ans,u);
                    int l=u,r=s[l].next;
                    if ((r-l)%2==0)//奇数
                        compare(l,r,(l+r)>>1);
                    else
                    {
                        compare(l,r,(l+r)>>1);
                        compare(l,r,(l+r+1)>>1);
                    }
                }*/
                if (!SS.empty())
                {
                    It=SS.begin();
                    int u=It->second;
                    update(g[u].a,g[u].b,g[u].ans,u);
                }

                if (ans<=1)
                {
                    it=S.begin();
                    if (it!=S.end())
                    {
                        int u=(*it);
                        if (aa>u)
                        {
                            if (s[u].c[0]==-1) {aa=u;bb=0;ans_l=s[u].last;}
                            else if (s[u].c[1]==-1) {aa=u;bb=1;ans_l=s[u].last;}
                        }
                    }
                }
                //printf("ans:%d %d %d\n",ans_l,aa,bb);
                a[++tot]=aa;
                Ins(ans_l,aa,bb);
            }
            print(tot);
        }
        else//走了一个人 
        {
            tot++;
            int x;
            scanf("%d",&x);
            int now=a[x];
            if (s[now].c[0]==x) Del(now,0);
            else Del(now,1);
        }
        /*for (int u=0;u<=n+1;u++)
            printf("%d:%d %d\n",u,s[u].last,s[u].next);
        printf("\n");*/
       /* for (int u=0;u<=n+1;u++)
            printf("%d:%d %d %d\n",u,g[u].a,g[u].b,g[u].ans);*/

    }
    return 0;
}

D2T1 BOARD

这题的话不难想到对节点标号
常用的技巧就是如果父亲是i,那么儿子就是2*i和2*i+1
你就可以得到这两个点的编号
先让深的一个跳到同一层是肯定的,这个应该知道吧。。
然后我们就考虑跳到了同一层的情况
不难发现,这种走法肯定是最优的
这里写图片描述
到这里和标解思路是一样的

下面是我yy的做法(正确性未知)

考虑到n很大,这些都没有关系,我们可以写高精度嘛。。
然后我们发现,你走上i层再走下来,代价是2*i
但是你可以节省2^i次方步。。
然后你就可以贪心地走,只要往上走优就往上走
然后就xjb算一下。。
但是考虑到高精度常数巨大,这个方法是实现难度也高。。
于是搞到一般我就放弃了

下面是官方的做法

在我放弃时候,我发现官方的代码贼短,我写几个高精度就快长过他了。。
那么当然是改行啦
题解是这么做的:
一个节点的表示方法大搞有一点点不一样
你用一个长度为n的数组表示
a[i]表示你从第i-1行走到第i行,然后往右走a[i]步
要注意的时候,你这个数组是要进位的,就是说要是你有一层的东西大于了2,那么就相当于上面走了1,然后注意了进位以后,其实就每一个数最大就是1
这样就可以很好地维护处什么向右走再向左走这种情况了
实现很简单,具体看代码。。
然后不难知道,他最后的深度是不会超过n的
然后我们可以暴力枚举他们要在那一层相遇
这个层数我们可以从上往下扫下来
然后我们可以知道他们在之前距离了多少
因为你要是在父亲距离了i,去到儿子就会变成2*i
然后你就看看在这一层的话,相遇的代价是多少
然后我们看下最优值就可以了,由于每一行最大走一步,所以你只需要枚举在那一层相遇就可以
当然如果我们现在的距离太大的话,我们就可以停止了

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
const int N=100005;
char s[2][N];//两条路径 
int a[2][N];//处理完后的路径
int len[2];//处理完后的路径长度
void pushup (int x,int y)
{
    a[x][y-1]=a[x][y-1]+a[x][y]/2-(a[x][y]%2==-1);
    a[x][y]=abs(a[x][y])%2;
}
void solve (int x)
{
    int n=strlen(s[x]);
    a[x][0]=1;int now=0;
    for (int u=0;u<n;u++)
    {
        if (s[x][u]=='1') a[x][++now]=0;
        if (s[x][u]=='2') a[x][++now]=1;
        if (s[x][u]=='L') a[x][now]--;
        if (s[x][u]=='R') a[x][now]++;
        if (s[x][u]=='U') {pushup(x,now);now--;}
    }
    len[x]=now;
    for (int u=now;u>=1;u--) pushup(x,u);
}
int main()
{
    scanf("%s%s",s[0],s[1]);
    solve(0);solve(1);
    int lalal=min(len[0],len[1]);
    /*printf("%d %d %d\n",len[0],len[1],lalal);
    for (int u=0;u<=len[0];u++) printf("%d ",a[0][u]);
    printf("\n");
    for (int u=0;u<=len[1];u++) printf("%d ",a[1][u]);*/
    int ans=(1<<20);
    int now=0;
    for (int u=0;u<=lalal&&now>-(1<<20)&&now<(1<<20);u++)
    {
        now=now*2+a[0][u]-a[1][u];
        ans=min(ans,abs(now)+2*(lalal-u));
    }
    printf("%d\n",ans+abs(len[0]-len[1]));
    return 0;
}

[CEOI2013]D1T3 SPLOT

这题的话,思路大部分是看题解的。。
然后似乎实现方式有一万个不一样。。但是反正我A了。。
讲道理,我完全看不懂标称在写smg

解法
不难想到处理这个可以维护一个站,当出现一个#的时候,就一直pop,直到出现一个S或P为止,然后我们就处理这个信息,把它变成一个新的停车场丢回栈里面
然后我们对每一个G维护5个值,front,back,both,lalal,none
分别表示这个
G里面的车都存在一条路径自由地到S
G里面的车都存在一条路径自由地到T
G里面的车都存在一条路径自由地到S或T
G里面的车都存在一条路径自由地到S或T,并且存在一条路径,使得S和T连通
G里面一辆车都没有
最多可以存在多少台车
不难发现 lalal<front,back<both
然后你就对于每个操作,相当于合并
然后你就大力地分类讨论一下就好了。。
也不是很多,我就写了 20+ 条式子,我相信各位看官自己也可以解决,我这里就不再赘述了
然而我并不会这么做,因为我是一个负责的人
那么我就说一下front怎么求,剩下的自己想把。。要不这个页面写不下了
先考虑串联的情况:
由于它是X–Y连起来,所以要是你想考虑Y里面的点,你X必须要留一条路给他
于是第一种可能取值就是
a[x].lalal+a[y].front
要是你不留路的话,那么就是
a[x].front+a[y].none
取max

然后我们考虑并联的情况
第一种情况就是S和T都是空的
第一种取值就是x和y的front
然后当然,我们还有x的both也是有可能有解的,就是通过T,再走Y走回去
那么答案就是
x的both和y的lalal
反过来也一样

第二种情况就是S有东西,T是空的
这个比较简单,就是x的none和y的none+1

第三种就是S空的,T是有的
那么就要留下一条路给T
那么就是一个front,一个lalal加上t的1

没有第四种了

然后就是这样,你就认真地推一下式子,调一下代码就可以了。。
至于输出方案,你可以倒回去,看看答案状态是怎么得出来的,然后在一步一步走回去,注意,当用到一个独立点的时候,他贡献的的是front, back或者both才是合法的,我这里调了一个多小时QAQ

实在不行的可以扒我代码:

#include<cstdio>
#include<bitset>
#include<cstdlib>
#include<stack>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=100005;
const int NN=N*0.42;
const int MAX=(1<<28);
char ss[N];
int len;
struct qy
{
    int s,t;//如果是O或者X,则保存它节点的编号
    int k;//它对应的是哪一个空间
    int front,back,both,lalal,none;
    int a,b,c,d;//它是由什么点决策过来的
    qy()
    {
        front=back=both=lalal=none=-MAX;
        a=b=c=d=-1;
    }
    //都在前面出去    都在后面出去     两边都可以出去      两边都可以出去且存在一条路使得ST相连   空集 
    //否则就保存它是什么类型   -1:P    -2:S 
}a[N*2];
bool ooo[N];//这个点是不是必要点 
int shen;
stack<int> S;
int g[10],lalal=0;//临时保存一下
bitset<NN> o[NN];
void series ()//串联 
{
    shen++;
    int x=g[2],y=g[1];

    a[shen].a=x;a[shen].b=y;
    a[shen].s=a[x].s;   a[shen].t=a[y].t;

    a[shen].front=max(a[x].lalal+a[y].front,a[x].front+a[y].none);

    a[shen].back=max(a[x].back+a[y].lalal,a[x].none+a[y].back);

    a[shen].both=a[x].front+a[y].back;
    a[shen].both=max(a[shen].both,a[x].both+a[y].lalal);
    a[shen].both=max(a[shen].both,a[x].lalal+a[y].both);

    a[shen].lalal=a[x].lalal+a[y].lalal;

    a[shen].none=a[x].none+a[y].none;

    S.push(shen);
}
void parallel ()
{
    shen++;
    int s=g[4],t=g[1];
    int x=g[3],y=g[2];
    a[shen].a=s;a[shen].b=t;a[shen].c=x;a[shen].d=y;

    a[shen].s=a[s].s;a[shen].t=a[t].t;
    if (a[s].none==0&&a[t].none==0)//S空T空
    {
        a[shen].front=max(a[shen].front,a[x].front+a[y].front);
        a[shen].front=max(a[shen].front,a[x].both+a[y].lalal);
        a[shen].front=max(a[shen].front,a[y].both+a[x].lalal);

        a[shen].back=max(a[shen].back,a[x].back+a[y].back);
        a[shen].back=max(a[shen].back,a[x].both+a[y].lalal);
        a[shen].back=max(a[shen].back,a[x].lalal+a[y].both);

        a[shen].both=max(a[shen].both,a[x].both+a[y].both);

        a[shen].lalal=max(a[shen].lalal,a[x].both+a[y].lalal);
        a[shen].lalal=max(a[shen].lalal,a[y].both+a[x].lalal);

        a[shen].none=max(a[shen].none,a[x].none+a[y].none);
    }
    if (a[s].none==0)//s空t有 
    {
    //  printf("OZY2");
        a[shen].front=max(a[shen].front,a[x].front+a[y].lalal+1);
        a[shen].front=max(a[shen].front,a[y].front+a[x].lalal+1);

        a[shen].back=max(a[shen].back,1+a[x].none+a[y].none);

        a[shen].both=max(a[shen].both,1+a[x].front+a[y].front);
    }
    if (a[t].none==0)//s有,t空
    {
        a[shen].front=max(a[shen].front,a[x].none+a[y].none+1);

        a[shen].back=max(a[shen].back,a[x].lalal+a[y].back+1);
        a[shen].back=max(a[shen].back,a[y].lalal+a[x].back+1);

        a[shen].both=max(a[shen].both,1+a[x].back+a[y].back);
    }
    a[shen].both=max(a[shen].both,2+a[x].none+a[y].none);
    S.push(shen);
}
void solve1 ()//把图构建出来 
{
    for (int u=1;u<=len;u++)
    {
        if (ss[u]=='|') continue;
        if (ss[u]=='#')//它是一个#号,也就是是一个终结符
        {
            lalal=0;
            while (!S.empty())
            {
                int x=S.top();
                if (a[x].s<0)//它是一个P
                    break;
                g[++lalal]=x;
                S.pop();
            }
            int x=S.top();S.pop();
            if (a[x].s==-1)//P类型
                parallel();
            else    series();
            /*for (int u=1;u<=shen;u++)
            {
                if (a[u].s<0) continue;
                printf("%d %d %d %d %d %d\n",u,a[u].front,a[u].back,a[u].both,a[u].lalal,a[u].none);
            }
            system("pause");*/
        }
        else S.push(u);
    }
    printf("%d\n",a[shen].front);
    /*for (int u=1;u<=num;u++)
        printf("%d %d\n",e[u].x,e[u].y);
    system("pause");*/
}
void dfs2 (int xx,int yy)//x,y是由什么得出来的 
{
    /*printf("%d %d\n",xx,yy);
    printf("%d %d %d %d\n",a[xx].a,a[xx].b,a[xx].c,a[xx].d);
    system("pause");*/
    if (xx<=len) 
    {
        if (yy<=3)   ooo[a[xx].s]=true;
        return ;
    }
    int shen=xx;
    if (a[xx].c==-1)
    {
        int x=a[xx].a,y=a[xx].b;

        if (yy==1)
        {
            if (a[shen].front==a[x].lalal+a[y].front) {dfs2(x,4);dfs2(y,1);return ;}    
            if (a[shen].front==a[x].front+a[y].none)  {dfs2(x,1);return ;}
        }
        if (yy==2)
        {
            if (a[shen].back==a[x].back+a[y].lalal) {dfs2(x,2);dfs2(y,4);return ;}
            if (a[shen].back==a[y].back) {dfs2(y,2);return ;}
        }
        if (yy==3)
        {
            if (a[shen].both==a[x].front+a[y].back) {dfs2(x,1);dfs2(y,2);return ;}
            if (a[shen].both==a[x].both+a[y].lalal) {dfs2(x,3);dfs2(y,4);return ;}
            if (a[shen].both==a[x].lalal+a[y].both) {dfs2(x,4);dfs2(y,3);return ;}
        }
        if (yy==4)
        {
            if (a[shen].lalal==a[x].lalal+a[y].lalal) {dfs2(x,4);dfs2(y,4);return ;}
        }
    }
    else
    {
        int s=a[xx].a,t=a[xx].b,x=a[xx].c,y=a[xx].d;
        if (a[s].none==0&&a[t].none==0)//S空T空
        {
            if (yy==1)
            {
                if (a[shen].front==a[x].front+a[y].front) {dfs2(x,1);dfs2(y,1);return ;}
                if (a[shen].front==a[x].both+a[y].lalal) {dfs2(x,3);dfs2(y,4);return ;}
                if (a[shen].front==a[y].both+a[x].lalal) {dfs2(x,4);dfs2(y,3);return ;}
            }
            if (yy==2)
            {
                if (a[shen].back==a[x].back+a[y].back) {dfs2(x,2);dfs2(y,2);return ;}
                if (a[shen].back==a[x].both+a[y].lalal) {dfs2(x,3);dfs2(y,4);return ;}
                if (a[shen].back==a[x].lalal+a[y].both) {dfs2(x,4);dfs2(y,3);return ;}
            }
            if (yy==3)
            {
                if (a[shen].both==a[x].both+a[y].both) {dfs2(x,3);dfs2(y,3);return ;}
            }
            if (yy==4)
            {
                if (a[shen].lalal==a[x].both+a[y].lalal) {dfs2(x,3);dfs2(y,4);return ;}
                if (a[shen].lalal==a[y].both+a[x].lalal) {dfs2(y,3);dfs2(x,4);return ;}
            }
        }
        if (a[s].none==0)//s空t有 
        {
            if (yy==1)
            {
                if (a[shen].front==a[x].front+a[y].lalal+1) {ooo[a[t].s]=true;dfs2(x,1);dfs2(y,4);return ;}
                if (a[shen].front==a[y].front+a[x].lalal+1) {ooo[a[t].s]=true;dfs2(x,4);dfs2(y,1);return ;}
            }
            if (yy==2)
            {
                if (a[shen].back==1+a[x].none+a[y].none) {ooo[a[t].s]=true;return ;}
            }
            if (yy==3)
            {
                if (a[shen].both==1+a[x].front+a[y].front) {ooo[a[t].s]=true;dfs2(x,1);dfs2(y,1);return ;}
            }
        }
        if (a[t].none==0)//s有,t空
        {
            if (yy==1)
            {
                if (a[shen].front==a[x].none+a[y].none+1) {ooo[a[s].s]=true;return ;}
            }
            if (yy==2)
            {
                if (a[shen].back==a[x].lalal+a[y].back+1) {ooo[a[s].s]=true;dfs2(x,4);dfs2(y,2);return ;}
                if (a[shen].back==a[y].lalal+a[x].back+1) {ooo[a[s].s]=true;dfs2(x,2);dfs2(y,4);return ;}
            }
            if (yy==3)
            {
                if (a[shen].both==1+a[x].back+a[y].back) {ooo[a[s].s]=true;dfs2(x,2);dfs2(y,2);return ;}
            }
        }
        if (yy==3)
        {
            if (a[shen].both==2+a[x].none+a[y].none) {ooo[a[s].s]=true;ooo[a[t].s]=true;return ;}
        }
    }
    return ;
}
int main()
{
    scanf("%s",ss+1);len=strlen(ss+1);

    for (int u=1;u<=len;u++)
    {
        if (ss[u]=='o')//这个开始没有车 
        {
            a[u].s=a[u].t=u;
            a[u].front=a[u].back=a[u].both=1;
            a[u].lalal=a[u].none=0;
        }
        if (ss[u]=='x') 
        {
            a[u].s=a[u].t=u;
            a[u].front=a[u].back=a[u].both=1;
            a[u].lalal=a[u].none=-MAX;
        }
        if (ss[u]=='P') a[u].s=-1;
        if (ss[u]=='S') a[u].s=-2;
        if (ss[u]=='|'||ss[u]=='#') a[u].s=-3;
    }
    shen=len;
    solve1();
/*  for (int u=1;u<=shen;u++)
    {
        if (a[u].s<0) continue;
        printf("%d s:%d t:%d front:%d back:%d both:%d lalal:%d none:%d\n",u,a[u].s,a[u].t,a[u].front,a[u].back,a[u].both,a[u].lalal,a[u].none);
    }
    system("pause");*/
    memset(ooo,false,sizeof(ooo));
    dfs2(shen,1);
    for (int u=1;u<=len;u++)
    {
        if (ss[u]=='o')//这个开始没有车 
        {
            if (ooo[a[u].s]) printf("x");
            else printf("o");
        }
        else printf("%c",ss[u]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值