• Codeforces Round #532 (Div. 2)


    D. Dasha and Chess

    交互题。题意: 有666个黑色的车和1个白色的国王在999*999的棋盘上,当白色的国王和任意一个黑色的车处于同一行,同一列的时候,白色国王胜利。白色的国王开始先行棋,NN执白,每一步可以横着,竖着或者斜着走一格,如果目标格子上已经有棋了那么就不能走。黑色的车每一次可以从一个格子走到任意的其他格子。每个玩家走2000步,如果白棋没法将军则黑棋胜利。现在你来执白棋,并想办法取得胜利。 

    题解:

    我们先把白棋走到棋盘的中间,然后一直向黑棋最多的角斜着走,这样一定可以将军。正确性显然。

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 const int maxn = 1005;
     4 int x,y,u,v,w,px[maxn],py[maxn],vis[maxn][maxn],sum[5],sum2[5];
     5 int dis[5][2]={0,0,-1,-1,-1,1,1,-1,1,1};
     6 void move_(int xx,int yy)
     7 {
     8     x+=xx;
     9     y+=yy;
    10     if(vis[x][y]) x-=xx;
    11     printf("%d %d
    ",x,y);
    12     fflush(stdout);
    13     scanf("%d%d%d",&u,&v,&w);
    14     if(u==-1&&v==-1&&w==-1) exit(0);
    15     vis[px[u]][py[u]]=0;
    16     vis[v][w]=1;
    17     px[u]=v;
    18     py[u]=w;
    19     return ;
    20 }
    21 int main()
    22 {
    23     scanf("%d%d",&x,&y);
    24     for(int i=1;i<=666;i++)
    25     {
    26         scanf("%d%d",&px[i],&py[i]);
    27         vis[px[i]][py[i]]=1;
    28     }
    29     int dir=-1;
    30     while(x<500) move_(1,0);
    31     while(y<500) move_(0,1);
    32     while(x>500) move_(-1,0);
    33     while(y>500) move_(0,-1);
    34     for(int i=1;i<=499;i++) for(int j=1;j<=499;j++) if(vis[i][j]) sum[1]++;
    35     for(int i=1;i<=499;i++) for(int j=501;j<=999;j++) if(vis[i][j]) sum[2]++;
    36     for(int i=501;i<=999;i++) for(int j=1;j<=499;j++) if(vis[i][j]) sum[3]++;
    37     for(int i=501;i<=999;i++) for(int j=501;j<=999;j++) if(vis[i][j]) sum[4]++;
    38     sum2[1]=sum[1]+sum[2]+sum[3];
    39     sum2[2]=sum[2]+sum[1]+sum[4];
    40     sum2[3]=sum[3]+sum[1]+sum[4];
    41     sum2[4]=sum[4]+sum[2]+sum[3];
    42     int maxx=0;
    43     for(int i=1;i<=4;i++)
    44     {
    45         if(sum2[i]>maxx)
    46         {
    47             maxx=sum2[i];
    48             dir=i;
    49         }
    50     }
    51     while(true) move_(dis[dir][0],dis[dir][1]);
    52     return 0;
    53 }
    View Code

    E. Andrew and Taxi

    题意:

    给你一个有边权的有向图,反转一条边的代价是这条边的边权,反转多个边的代价是所有反转边里面边权最大的那条边的边权,问让这个图不存在环的最小代价,以及被反转的边的编号。

    题解:

    我们先这么想,给出一个最小代价Min,我们如何判断是否有环?因为代价小于等于Min的边都可以选择反转,所以只要对于边权大于Min的边跑拓扑排序,如果没环就说明Min是可行的。那么反转哪些边呢?我们现在已经得到了拓扑序,然后只要对于每一条wi<=Min的从u到v的边,如果topo[v]<topo[u],那么这条边就需要被反转。显然Min是可以通过二分获得的。

     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <cstring>
     5 #include <queue>
     6 #include <vector>
     7 
     8 using namespace std;
     9 const int maxn=100000+100;
    10 int n,m,sz;
    11 int head[maxn],Next[maxn],to[maxn],w[maxn],num[maxn];
    12 void init(){
    13     sz=0;
    14     memset(head,-1,sizeof(head));
    15 }
    16 void add_edge(int a,int b,int c,int cnt){
    17     ++sz;
    18     to[sz]=b;w[sz]=c;num[sz]=cnt;Next[sz]=head[a];head[a]=sz;
    19 }
    20 int topo[maxn],Topo[maxn],vis[maxn],cnt;
    21 
    22 bool is_circle(int u,int mid){
    23     vis[u]=-1;
    24     for(int i=head[u];i!=-1;i=Next[i]){
    25         int v=to[i];
    26         if(w[i]<=mid)continue;
    27         if(vis[v]==-1)return true;
    28         if(!vis[v])
    29             if(is_circle(v,mid))
    30                 return true;
    31     }
    32     topo[cnt]=u;
    33     Topo[u]=cnt--;
    34     vis[u]=1;
    35     return false;
    36 }
    37 int Max;
    38 int main(){
    39     init();
    40     scanf("%d%d",&n,&m);
    41     for(int i=1;i<=m;i++){
    42         int a,b,c;
    43         scanf("%d%d%d",&a,&b,&c);
    44         Max=max(Max,c);
    45         add_edge(a,b,c,i);
    46     }
    47     cnt=n;
    48 //    for(int i=1;i<=n;i++){
    49 //        printf("%d ",topo[i]);
    50 //    }
    51     int l=0,r=Max,ans=0;
    52     while(l<=r){
    53         int mid=l+(r-l)/2;
    54         memset(vis,0,sizeof(vis));
    55         int flag=0;
    56         cnt=n;
    57         for(int i=1;i<=n;i++){
    58             if(!vis[i]){
    59                 if(is_circle(i,mid)){
    60                    flag=1;
    61                    break;
    62                 }
    63             }
    64         }
    65 
    66         if(!flag){
    67             ans=mid;
    68             r=mid-1;
    69         }else{
    70             l=mid+1;
    71         }
    72     }
    73     //printf("%d
    ",ans);
    74     vector<int>ANS;
    75     memset(vis,0,sizeof(vis));
    76     cnt=n;
    77     for(int i=1;i<=n;i++)
    78         if(!vis[i])
    79             is_circle(i,ans);
    80 
    81     for(int i=1;i<=n;i++){
    82         for(int j=head[i];j!=-1;j=Next[j]){
    83             int v=to[j];
    84            // printf("%d %d %d %d %d
    ",i,v,w[j],Topo[i],Topo[v]);
    85             if(w[j]<=ans&&Topo[v]<Topo[i]){
    86                 ANS.push_back(num[j]);
    87             }
    88         }
    89     }
    90     printf("%d %d
    ",ans,ANS.size());
    91     for(int i=0;i<ANS.size();i++){
    92         printf("%d ",ANS[i]);
    93     }
    94 return 0;
    95 }
    View Code

    F.题意:

    给出n个数字ci和q个询问,每次询问给出li和ri,需要你求出从区间[li,ri]内选出一些数字,异或值最大。

    题解:

    这个题一看就是线性基。我们先来看一下简化版,也是线性基最经典的应用之一。如果是只有一次询问,问从这n个数字中选出一些数使得异或值最大。该怎么做?我们先求出这n个数字的线性基,然后从高位开始异或如果异或上这个值数变大那么就异或上。想想为什么?因为异或上高位的可能会影响异或低位的,但是结果一定不会更差。我们回到这个题,我们考虑离线的做法,将询问按照右端点排序,然后从1到n扫开始构造线性基,但是和正常构造的区别是,这里构造的时候,对于当前的元素,它所在线性基的位置一定是越高越好的。那么我们这里就有一个“替换”操作。详细的可以看代码。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <vector>
    
    using namespace std;
    typedef long long LL;
    const int maxn=500000+10;
    int n,q;
    int c[maxn],x[100],l[100];
    struct Seg{
        int l,r;
    }seg[maxn];
    LL ans[maxn];
    vector<int>en[maxn];
    
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&c[i]);
        }
        scanf("%d",&q);
        for(int i=1;i<=q;i++){
            scanf("%d%d",&seg[i].l,&seg[i].r);
            en[seg[i].r].push_back(i);
        }
    
        for(int i=1;i<=n;i++){
            int pos=i;
            for(int j=62;j>=0;j--){
                if(((c[pos]>>j)&1)==0)continue;
                if(!x[j]){x[j]=c[pos];l[j]=pos;break;}
                else if(l[j]<pos){
                    //swap(x[j],c[pos]);
                    x[j]=c[pos];
                    swap(pos,l[j]);
                }
                c[pos]^=x[j];
            }
    
            for(int j=0;j<en[i].size();j++){
                ans[en[i][j]]=0;
                for(int k=62;k>=0;k--){
                    if(l[k]>=seg[en[i][j]].l){
                        ans[en[i][j]]=max(ans[en[i][j]],x[k]^ans[en[i][j]]);
                    }
                }
            }
        }
    
        for(int i=1;i<=q;i++){
            printf("%I64d
    ",ans[i]);
        }
    return 0;
    }
    View Code
  • 相关阅读:
    [BZOJ] 1623: [Usaco2008 Open]Cow Cars 奶牛飞车
    [BZOJ] 3631: [JLOI2014]松鼠的新家
    [BZOJ] 1775: [Usaco2009 Dec]Vidgame 电视游戏问题
    [BZOJ] 1619: [Usaco2008 Nov]Guarding the Farm 保卫牧场
    [Codeforces] #432 div.2 (Virtual)
    [BZOJ] 1819: [JSOI]Word Query电子字典
    [Codeforces] #436 E. Fire
    [Codeforces] #436 D. Make a Permutation!
    [Codeforces] #436 C. Bus
    [Codeforces] #436 B. Polycarp and Letters
  • 原文地址:https://www.cnblogs.com/LQLlulu/p/10384875.html
Copyright © 2020-2023  润新知