zoukankan      html  css  js  c++  java
  • XIII Open Cup named after E.V. Pankratiev. GP of Saratov

    A. Box Game

    注意到局面总数不超过$50000$,而且每次操作都会改变石子的奇偶性,因此按奇偶可以将状态建成二分图,然后求出最大匹配。

    如果状态数是偶数,那么先手必胜,策略就是每次走匹配边,那么对手不能通过匹配边走回来,因此所有匹配边你都能走掉。

    如果状态数是奇数,那么如果此时有奇数个石子,也是先手必胜,因为最后对手会遭遇怎么走都会回到以前走过的局面的困境。

    选择完先后手之后,每次按匹配边走下去即可。

    B. Circle of Stones

    首先将环倍长,破环成链,那么剩下的子串要满足相邻字符不同且首尾字符不同。

    通过双指针求出每一段极长的子串,满足相邻字符不同,设这一段长度为$len$,从$2$到$len$枚举剩下的串的长度$L$,若该子串长度为$len-L+1$的前后缀不能完全匹配,则说明存在距离为$L-1$的位置不同,也就能充当首尾,Hash判断即可。

    时间复杂度$O(n)$。

    #include<cstdio>
    #include<cstring>
    typedef long long ll;
    const int N=2000010,D=233,P=1000000009;
    int C,n,m,i,j,k,len;char a[N],ans[N];ll pow[N],f[N];
    inline ll hash(int l,int r){return((f[r]-f[l-1]*pow[r-l+1])%P+P)%P;}
    int main(){
      for(pow[0]=i=1;i<N;i++)pow[i]=pow[i-1]*D%P;
      while(~scanf("%s",a+1)){
        n=strlen(a+1);m=n+n;
        for(i=1;i<=n;i++)a[i+n]=a[i];
        for(i=1;i<=m;i++)f[i]=(f[i-1]*D+a[i])%P;
        for(i=0;i<n;i++)ans[i]='0';
        for(i=1;i<=m;i=j+1){
          for(j=i;j<m&&a[j]!=a[j+1];j++);
          len=j-i+1;
          for(k=2;k<=len&&k<=n;k++)if(hash(i,i+len-k)!=hash(j-len+k,j))ans[n-k]='1';
        }
        for(printf("Case %d: ",++C),i=0;i<n-1;i++)putchar(ans[i]);puts("1");
      }
      return 0;
    }
    

      

    C. Expression with Sets

    留坑。

    D. Heating System

    留坑。

    E. Islands

    留坑。

    F. Longest Two Graphs Common String

    设$f[i][j][0]$表示选出的路径里,第一张图中最后一个点是$i$,第二张图中最后一个点是$j$的最大长度。

    设$f[i][j][1]$表示选出的路径里,第一张图中最后一个点再往后乱走一步到了$i$,第二张图中最后一个点是$j$的最大长度。

    则对于$f[i][j][0]$,只需要枚举指向$j$的边,用$f[i][j'][1]$转移;对于$f[i][j][1]$,只需要枚举指向$i$的边,用$f[i'][j][0]$转移。

    时间复杂度$O(n(n+m))$。

    #include<cstdio>
    const int N=505,M=4010;
    int T,n1,n2,m,i,j,k,flag,ans,X,Y,q[N*N][2];
    int f[N][N][2],pre[N][N][2];
    bool v[N][N][2],vis[N][N][2];
    struct G{
      int n,g[N],v[M],nxt[M],ed;
      int i,x,y;
      char a[N];
      void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
      void init(int _n,int m){
        n=_n;
        scanf("%s",a+1);
        for(ed=0,i=1;i<=n;i++)g[i]=0;
        while(m--)scanf("%d%d",&x,&y),add(y,x);
      }
    }G1,G2;
    void dp(int x,int y,int z){
      if(vis[x][y][z])flag=1;
      if(flag)return;
      if(v[x][y][z])return;
      vis[x][y][z]=v[x][y][z]=1;
      int&t=f[x][y][z],&p=pre[x][y][z];
      t=-1,p=0;
      if(z==0){
        if(G1.a[x]==G2.a[y]){
          t=0;
          for(int i=G2.g[y];i;i=G2.nxt[i]){
            int k=G2.v[i];
            dp(x,k,z^1);
            if(f[x][k][z^1]>t)t=f[x][k][z^1],p=k;
          }
          if(~t)t++;
        }
      }else{
        for(int i=G1.g[x];i;i=G1.nxt[i]){
          int k=G1.v[i];
          dp(k,y,z^1);
          if(f[k][y][z^1]>t)t=f[k][y][z^1],p=k;
        }
      }
      vis[x][y][z]=0;
    }
    int main(){
      while(~scanf("%d%d",&n1,&m)){
        G1.init(n1,m);
        scanf("%d%d",&n2,&m);
        G2.init(n2,m);
        for(i=1;i<=n1;i++)for(j=1;j<=n2;j++)for(k=0;k<2;k++)v[i][j][k]=vis[i][j][k]=0;
        ans=flag=0;
        for(i=1;i<=n1;i++)for(j=1;j<=n2;j++){
          dp(i,j,0);
          if(f[i][j][0]>ans)ans=f[i][j][0],X=i,Y=j;
        }
        printf("Case %d: ",++T);
        if(flag)puts("-1");else{
          printf("%d
    ",ans);
          for(i=ans;i;i--){
            q[i][0]=X,q[i][1]=Y;
            Y=pre[X][Y][0];
            X=pre[X][Y][1];
          }
          for(i=1;i<=ans;i++)printf("%d%c",q[i][0],i<ans?' ':'
    ');
          for(i=1;i<=ans;i++)printf("%d%c",q[i][1],i<ans?' ':'
    ');
        }
      }
      return 0;
    }
    

      

    G. Lyndon Words

    找规律构造,可以$O(n)$生成字典序下一个,暴力生成出字典序前$r$小的所有串即可。

    时间复杂度$O(nr)$。

    H. Temperature

    状压DP。

    时间复杂度$O(n2^n)$。

    I. Editor 2

    留坑。

    J. Tourist Problem

    留坑。

    K. Ant versus Woodpecker

    显然答案就是虚树上度数$>1$的点的深度的最大值,用ETT维护dfs序并支持查询lca即可。

    时间复杂度$O((m+sum k)log n)$。

    #include<cstdio>
    #include<algorithm>
    #include<set>
    using namespace std;
    const int N=400010;
    int C,n,m,i,x,g[N],Nxt[N];
    int vis[N],a[N],dfn[N],deg[N],t,q[N];
    int id[N];
    int d[N],st[N],en[N],pre[N],nxt[N],val[N],md[N],size[N],son[N][2],f[N],tot,root;
    set<int>T;
    inline void up(int x){
      md[x]=val[x];
      size[x]=1;
      if(son[x][0]){
        if(d[md[son[x][0]]]<d[md[x]])md[x]=md[son[x][0]];
        size[x]+=size[son[x][0]];
      }
      if(son[x][1]){
        if(d[md[son[x][1]]]<d[md[x]])md[x]=md[son[x][1]];
        size[x]+=size[son[x][1]];
      }
    }
    inline void rotate(int x){
      int y=f[x],w=son[y][1]==x;
      son[y][w]=son[x][w^1];
      if(son[x][w^1])f[son[x][w^1]]=y;
      if(f[y]){
        int z=f[y];
        if(son[z][0]==y)son[z][0]=x;
        if(son[z][1]==y)son[z][1]=x;
      }
      f[x]=f[y];son[x][w^1]=y;f[y]=x;up(y);
    }
    inline void splay(int x,int w){
      while(f[x]!=w){
        int y=f[x];
        if(f[y]!=w){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
        rotate(x);
      }
      if(!w)root=x;
      up(x);
    }
    inline int getrank(int x){
      splay(x,0);
      return size[son[x][0]];
    }
    inline void addnode(int x,int y){//x father is y
      d[x]=d[y]+1;
      int z=nxt[st[y]];
      splay(st[y],0);
      splay(z,root);
      son[z][0]=++tot;
      val[tot]=x;
      f[tot]=z;
      st[x]=tot;
      id[tot]=x;
      son[st[x]][1]=++tot;
      f[tot]=st[x];
      val[tot]=y;
      en[x]=tot;
      up(tot);
      up(st[x]);
      up(z);
      up(root);
      nxt[root]=st[x];
      nxt[st[x]]=en[x];
      nxt[en[x]]=z;
      pre[z]=en[x];
      pre[en[x]]=st[x];
      pre[st[x]]=root;
    }
    void dfsdel(int x){
      if(!x)return;
      if(id[x])T.insert(id[x]);
      dfsdel(son[x][0]);
      dfsdel(son[x][1]);
    }
    inline void delsubtree(int x){
      splay(pre[st[x]],0);
      splay(nxt[en[x]],root);
      int z=son[root][1];
      nxt[root]=z;
      pre[z]=root;
      dfsdel(son[z][0]);
      son[z][0]=0;
      up(z);
      up(root);
    }
    void show(int x){
      if(!x)return;
      show(son[x][0]);
      printf("%d ",val[x]);
      show(son[x][1]);
    }
    inline int lca(int x,int y){
      if(x==y)return x;
      if(x==1||y==1)return 1;
      if(getrank(st[x])>getrank(st[y]))swap(x,y);
      splay(pre[st[x]],0);
      splay(nxt[st[y]],root);
      return md[son[son[root][1]][0]];
    }
    int build(int l,int r,int fa){
      int mid=(l+r)>>1;
      f[mid]=fa;
      if(l<mid)son[mid][0]=build(l,mid-1,mid);
      if(r>mid)son[mid][1]=build(mid+1,r,mid);
      up(mid);
      return mid;
    }
    inline bool cmp(int x,int y){return dfn[x]<dfn[y];}
    void dfs(int x){
      for(int i=g[x];i;i=Nxt[i]){
        d[i]=d[x]+1;
        st[i]=++tot;
        val[tot]=i;
        dfs(i);
        en[i]=++tot;
        val[tot]=x;
      }
    }
    inline int getid(){
      int x=*T.begin();
      T.erase(x);
      return x;
    }
    int main(){
      while(~scanf("%d",&n)){
        st[1]=1;
        val[1]=1;
        tot=1;
        for(i=2;i<=n;i++){
          scanf("%d",&x);
          Nxt[i]=g[x];
          g[x]=i;
        }
        dfs(1);
        en[1]=++tot;
        val[tot]=1;
        for(i=1;i<tot;i++){
          pre[i+1]=i;
          nxt[i]=i+1;
        }
        for(i=1;i<=n;i++)id[st[i]]=i;
        root=build(1,tot,0);
        int mm;
        scanf("%d",&mm);
        int lim=n+mm;
        T.clear();
        for(i=n+1;i<=n+mm;i++)T.insert(i);
        int last=0;
        printf("Case %d:",++C);
        while(mm--){
          char op[5];
          scanf("%s",op);
          if(op[0]=='+'){
            int x;
            scanf("%d",&x);
            int y=getid();
            x+=last;
            addnode(y,x);
          }
          if(op[0]=='-'){
            int x;
            scanf("%d",&x);
            delsubtree(x);
          }
          if(op[0]=='?'){
            //show(root);puts("");
            scanf("%d",&m);
            int cnt=1;
            a[1]=1;
            vis[1]=1;
            dfn[1]=getrank(st[1]);
            while(m--){
              scanf("%d",&x);
              if(!vis[x]){
                a[++cnt]=x,vis[x]=1;
                dfn[x]=getrank(st[x]);
              }
            }
            //for(i=1;i<=cnt;i++)printf("%d ",a[i]);puts("");
            sort(a+1,a+cnt+1,cmp);
            int now=cnt;
            for(i=1;i<cnt;i++)if(!vis[x=lca(a[i],a[i+1])]){
              vis[a[++now]=x]=1;
              dfn[x]=getrank(st[x]);
            }
            sort(a+1,a+now+1,cmp);
            //for(i=1;i<=now;i++)printf("%d ",a[i]);puts("");
            last=-1;
            for(q[t=1]=1,i=2;i<=now;q[++t]=a[i++]){
              while(lca(a[i],q[t])!=q[t])t--;
              deg[q[t]]++;
              if(deg[q[t]]>1)last=max(last,d[q[t]]);
              //printf("edge %d %d
    ",q[t],a[i]);
            }
            printf(" %d",last);
            for(i=1;i<=now;i++)vis[a[i]]=deg[a[i]]=0;
          }
        }
        puts("");
        for(i=1;i<=lim;i++)st[i]=en[i]=d[i]=g[i]=0;
        for(i=0;i<=tot+1;i++)id[i]=pre[i]=nxt[i]=val[i]=md[i]=size[i]=son[i][0]=son[i][1]=f[i]=0;
        tot=root=0;
      }
      return 0;
    }
    

      

  • 相关阅读:
    PAT (Advanced Level) 1080. Graduate Admission (30)
    PAT (Advanced Level) 1079. Total Sales of Supply Chain (25)
    PAT (Advanced Level) 1078. Hashing (25)
    PAT (Advanced Level) 1077. Kuchiguse (20)
    PAT (Advanced Level) 1076. Forwards on Weibo (30)
    PAT (Advanced Level) 1075. PAT Judge (25)
    PAT (Advanced Level) 1074. Reversing Linked List (25)
    PAT (Advanced Level) 1073. Scientific Notation (20)
    PAT (Advanced Level) 1072. Gas Station (30)
    PAT (Advanced Level) 1071. Speech Patterns (25)
  • 原文地址:https://www.cnblogs.com/clrs97/p/5701534.html
Copyright © 2011-2022 走看看