zoukankan      html  css  js  c++  java
  • Mail.Ru Cup 2018 Round 2 Solution

    A. Metro

    Solved.

    题意:

    有两条铁轨,都是单向的,一条是从左往右,一条是从右往左,Bob要从第一条轨道的第一个位置出发,Alice的位置处于第s个位置,有火车会行驶在铁轨上,一共有n个站点,1表示火车会在该站点停下,0表示不会,求Bob能否到达地s个位置(到达任意一边即可)

    思路:

    如果第一条铁轨的第一个位置为0,或者第s个位置的两条铁轨都不停,那么答案显然是$"No"$

    再考虑第一条铁轨上所有为1的位置都可以到达

    再考虑两条轨道是否有同一个站点都都会停下的,那么就可以到达第二条轨道,并且该站点的左边的会停下的站点都可以到达

    再判断一下s站点有没有被标记即可。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define N 1010
     5 int n, s, a[N], b[N];
     6 int vis[N];
     7 
     8 bool solve()
     9 {
    10     if (a[1] == 0) return false;
    11     if (a[s] == 0 && b[s] == 0) return false;
    12     for (int i = 1; i <= n; ++i) if (a[i]) vis[i] = 1;
    13     bool flag = false;
    14     for (int i = n; i >= 1; --i)
    15     {
    16         if (a[i] && b[i]) flag = 1;
    17         if (flag && b[i]) vis[i] = 1; 
    18     }
    19     return vis[s];
    20 }
    21 
    22 int main()
    23 {
    24     while (scanf("%d%d", &n, &s) != EOF)
    25     {
    26         memset(vis, 0, sizeof vis);
    27         for (int i = 1; i <= n; ++i) scanf("%d", a + i);
    28         for (int i = 1; i <= n; ++i) scanf("%d", b + i);
    29         puts(solve() ? "YES" : "NO");    
    30     }
    31     return 0;
    32 }
    View Code

    B. Alice and Hairdresser

    Solved,

    题意:

    Alice有$n根头发,只有长度 > l 的头发才需要减,并且有相邻多根头发的长度都 > l,那么这几根可以一刀剪掉$

    现在有两种操作,第一种是询问Alice如果要剪头发,最少需要减几刀,第二种是第$p$根头发增加了$d$的长度。

    思路:

    头发增加时,如果这根头发已经$ > l 了$ 那么不需要操作

    反之,则判断一下,左右两边的头发长度

    如果左右两边头发长度都$> l$ 那么下剪刀的次数 - 1  因为左右两边本来是两个连通块,现在连成一个。

    如果有一边$ > l$ 有一边不是,那么下剪刀次数不变

    如果两边都$ < l$ 那么下剪刀次数+1

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define N 100010
     6 int n, m, res; 
     7 ll l, a[N];
     8 
     9 int main()
    10 {
    11     while (scanf("%d%d%lld", &n, &m, &l) != EOF)
    12     {
    13         res = 0;
    14         for (int i = 1; i <= n; ++i) 
    15         {
    16             scanf("%lld", a + i);
    17             if (a[i] > l && a[i - 1] <= l) ++res; 
    18         }
    19         for (int i = 1, t, p, d; i <= m; ++i)
    20         {
    21             scanf("%d", &t);
    22             if (t == 0) printf("%d
    ", res);
    23             else 
    24             {
    25                 scanf("%d%d", &p, &d);
    26                 if (a[p] <= l && a[p] + d > l)  
    27                 {
    28                     if (a[p - 1] > l && a[p + 1] > l) --res;
    29                     else if (a[p - 1] > l || a[p + 1] > l);
    30                     else ++res;                    
    31                 }
    32                 a[p] += d;  
    33             }
    34         }
    35     }
    36     return 0;
    37 }
    View Code

    C. Lucky Days

    Upsolved.

    题意:

    定义一个三元组$<l, r, t>$ 表示一个周期为$t$,第$[l, r]$天里面是幸运天,现在给出$Alice 和 Bob$的两个三元组,求两人最长的连续相同的幸运天数。

     思路:

    考虑两个人的起点之差是 $gcd(ta, tb)$ 用一个人的起点去逼近另一个人的起点,然后求一下答案。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 ll la, lb, ra, rb, ta, tb;
     6 
     7 ll gcd(ll a, ll b)
     8 {
     9     return b ? gcd(b, a % b) : a;
    10 }
    11 
    12 ll calc(ll la, ll ra, ll lb, ll rb)
    13 {
    14     return max(0ll, min(ra, rb) - max(la, lb) + 1);  
    15 }
    16     
    17 int main()
    18 {
    19     while (scanf("%lld%lld%lld", &la, &ra, &ta) != EOF)
    20     {
    21         scanf("%lld%lld%lld", &lb, &rb, &tb);
    22         if (la > lb) 
    23         {
    24             swap(la, lb); 
    25             swap(ra, rb);
    26             swap(ta, tb);
    27         }
    28         ll g = gcd(ta, tb);
    29         ll gap = ra - la;
    30         la += ((lb - la) / g) * g;
    31         ra = la + gap;
    32         printf("%lld
    ", max(calc(la, ra, lb, rb), calc(la + g, ra + g, lb, rb)));
    33     }
    34     return 0;
    35 }
    View Code

    D. Refactoring

    Unsolved.

    E. Segments on the Line

    Unsolved.

    F. Tree and XOR

    Upsolved.

    题意:

    在一棵树种,一共有$n^2$个任意两点间的简单路径异或和,求第k大。

     思路:

    显然,路上任意两点路径异或和就是两个点到根的异或和再异或

    再考虑求第k大,可以二分,然后去找到有多少个比这个数小的数,如果$<= k 那么这个数就可能可以作为答案$

    但这样的过程是$O(n{log^n}^2)$,显然不行

    但是其实可以直接一位一位考虑,从高位到低位逐位确定,枚举当前为是否为1,如果为1,那么异或后当前为为0的都是比当前数小的数,逐步确定下去即可。

    但是注意到,这个过程可以用$01Trie 完成,但是完整的01Trie空间开不下$

    又考虑我们每一次确定的时候,只会用到上一层和当前层的状态,所有用滚动数组即可。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define N 1000010
     6 int n, rt[N], prt[N], ch[N][2], num[N], cnt;  
     7 ll w[N], k;
     8 
     9 void init()
    10 {
    11     memset(num, 0, sizeof num);
    12     memset(ch, 0, sizeof ch);
    13 }
    14 
    15 int main()
    16 {
    17     while (scanf("%d%lld", &n, &k) != EOF)
    18     {
    19         init();
    20         for (int i = 2, p; i <= n; ++i)
    21         {
    22             scanf("%d%lld", &p, w + i);
    23             w[i] ^= w[p];
    24         }
    25         ll res = 0;
    26         for (int i = 1; i <= n; ++i) rt[i] = prt[i] = 1; cnt = 1;
    27         for (int s = 62; s >= 0; --s)
    28         {
    29             for (int i = 1; i <= cnt; ++i) ch[i][0] = ch[i][1] = num[i] = 0; cnt = 1;
    30             for (int i = 1; i <= n; ++i)
    31             {
    32                 int id = (w[i] >> s) & 1;
    33                 if (!ch[rt[i]][id]) ch[rt[i]][id] = ++cnt;
    34                 rt[i] = ch[rt[i]][id];
    35                 ++num[rt[i]];
    36             }    
    37             ll sum = 0;
    38             for (int i = 1; i <= n; ++i)
    39             {
    40                 int id = (w[i] >> s) & 1;
    41                 sum += num[ch[prt[i]][id]];
    42             }
    43             if (sum < k)
    44             {
    45                 res |= 1ll << s;
    46                 k -= sum;
    47                 for (int i = 1; i <= n; ++i)
    48                 {
    49                     int id = (w[i] >> s) & 1;
    50                     prt[i] = ch[prt[i]][id ^ 1];
    51                 }
    52             }
    53             else
    54             {
    55                 for (int i = 1; i <= n; ++i)
    56                 {
    57                     int id = (w[i] >> s) & 1;
    58                     prt[i] = ch[prt[i]][id];
    59                 }
    60             }
    61         }
    62         printf("%lld
    ", res);
    63     }    
    64     return 0;
    65 }
    View Code

    G. Jellyfish Nightmare

    Unsolved.

  • 相关阅读:
    Objective-C 复合
    useContext的使用
    context的使用
    redux使用(二)
    redux使用(一)
    React class & function component 的区别
    combineReducers使用
    gnvm使用(未使用成功)
    React相关知识点
    eslint简单使用&&eslint与webpack结合使用
  • 原文地址:https://www.cnblogs.com/Dup4/p/9961425.html
Copyright © 2011-2022 走看看