zoukankan      html  css  js  c++  java
  • 2020大一个人赛(9)题解

    A-Rooms and Passages Gym 102215A

    题意:给n个数,从起点出发,一直往右走,遇到一个前面出现过其相反数的正数就停下,问对于每个起点都能走多少步。

    思路:倒着去递推

    • 如果该点是正数,肯定能顺着走,ans[i]=ans[i+1]+1;
    • 如果该点是负数,判断该相反数是否存在,若不存在,还是ans[i]=ans[i+1]+1,否则走到前面出现过其相反数的正数,r = min(r, b[-a[i]] - 1);      ans[i] = r - i + 1;

    具体看代码怎么模拟吧

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<vector>
     4 #include<cstring>
     5 using namespace std;
     6 #define ll long long
     7 const int N = 1000005;
     8 const int mod = 1e9 + 7;
     9 ll a[N],b[N],c[N],ans[N];
    10 int main()
    11 {
    12     ll i, j, k;
    13     ll n, m, t,x,sum=0;
    14     cin >> n;
    15     for (i = 1; i <= n; i++)
    16         cin >> a[i];
    17     ll r = n + 1;
    18     for (i = n; i >= 1; i--)
    19     {
    20         if (a[i] > 0)
    21         {
    22             ans[i] = ans[i + 1] + 1;
    23            b[a[i]] = i;//记录a[i]出现的最靠前的位置
    24         }
    25         else
    26         {
    27             if (!b[-a[i]])
    28             {
    29                 ans[i] = ans[i + 1] + 1;//在i后边没有这种颜色,可通过就是下一个情况加1
    30             }
    31             else
    32             {
    33                 r = min(r, b[-a[i]] - 1);//寻找能到达的最靠前的位置
    34                 ans[i] = r - i + 1;
    35             }
    36         }
    37     }
    38     for (i = 1; i <= n; i++)
    39         cout << ans[i] << " ";
    40    
    41 
    42 }

    B - Rearrange Columns Gym - 102215B

    题意:有两行字符串,有‘#’和‘.’,问能否重排(列一起移),使他们连在一起。

    思路:模拟即可,判断一下两行都是#的一定能有办法连在一起,或者上面有#下面(相反也是),然后连完之后你怎么排也无所谓(样例不一定就是唯一解)

    详情看代码吧!

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<vector>
     4 #include<map>
     5 #include<cstring>
     6 using namespace std;
     7 #define ll long long
     8 const int N = 1e5+5;
     9 const int mod = 1e9 + 7;
    10 int main()
    11 {
    12     ll i, j, k;
    13     ll  m, t;
    14     string s1, s2;
    15     cin >> s1 >> s2;
    16     ll n = s1.size();
    17     ll a = 0, b = 0, c = 0;
    18     for (i = 0; i < n; i++)
    19     {
    20         if (s1[i] == '#' && s2[i] == '#')a++;
    21         else if (s1[i] == '#' && s2[i] == '.')b++;
    22         else if (s1[i] == '.' && s2[i] == '#')c++;
    23     }
    24     if (a || (b && !c) || (c && !b))
    25     {
    26         cout << "YES" << endl;
    27         {
    28             for (i = 0; i < n - a - b - c; i++)
    29                 cout << '.';
    30             for (i = 0; i < a + b; i++)
    31                 cout << '#';
    32             for (i = 0; i < c; i++)
    33                 cout << '.';
    34             cout << endl;
    35             for (i = 0; i < n - a - b - c; i++)
    36                 cout << '.';
    37             for (i = 0; i < b; i++)
    38                 cout << '.';
    39             for (i = 0; i < a+c; i++)
    40                 cout << '#';
    41             cout << endl;
    42         }
    43     }
    44     else
    45         cout << "NO" << endl;
    46    
    47 
    48 }

    C - Jumps on a Circle Gym - 102215C

     题意:一个环从0到p-1,从0开始每次跳1,2,3,···,n-1,n步,问跳n步之后会有多少个位置访问过。

    思路:弄一个vis数组,表示访问过的点,注意p为1e7,数组开大点(RE很多次),或者用map记录,去到没标过的点就+1

       然后若n>2p,2p次后又一定回到点原点,然后2p+1,2p+2步的效果相当于1,2步(%p就知道了)

     这时候观众朋友们告诉我,为什么不是p次呢,因为

     你带4进去就知道原因了。所以最少走min(n,2p)次就能知道访问过的点了。

    详情问代码吧!

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<vector>
     4 #include<cstring>
     5 using namespace std;
     6 #define ll long long
     7 const int N = 1e7+5;
     8 const int mod = 1e9 + 7;
     9 ll vis[N];
    10 int main()
    11 {
    12     ll i, j, k;
    13     ll p,n, m, t,x,sum=0;
    14     cin >> p >> n;
    15     vis[0] = 1;
    16     ll now = 0;
    17     for (i = 1; i <= min(n, 2 * p); i++)
    18     {
    19         now = (now + i) % p;
    20         vis[now] = 1;
    21     }
    22     for (i = 0; i < p; i++)
    23         sum += vis[i];
    24     cout << sum << endl;
    25    
    26 
    27 }

     D - Country Division Gym - 102215D

    题意:给你n点,n-1条边(相当于一棵树),每次询问给你一些点染红色,一些点蓝色,问能否通过放些障碍物在边上,使得所有红色的点互相连通,所有蓝色的点连通,而不互相碰见。

    思路:LCA(最近公共祖先),就是找公共的父节点,这题是一道LCA经典题,各位可以认真细品题目,get到新知识点你就会成长,至于问怎么实现LCA原理的,我没了解过OvO

     解释下LCA,比如4和5的公共父节点是2;4和6的LCA是1;5和7的LCA是1;6和7的LCA是3.

    正解思路:

    • 先求红色点的lca,再求蓝色点的lca,如果两个lca不在同一棵子树,那么可以分隔开来。
    • 如果两个lca有祖先关系,比如红色lca和蓝色lca的lca就是红色lca,那么如果红色点都在红色lca指向蓝色lca的另一条边上,那就可以,否则,说明有红色点在蓝色点的子树下

    下面看代码吧

      1 #include<iostream>
      2 #include<algorithm>
      3 #include<cmath>
      4 #include<cstdio>
      5 #include<cstdlib>
      6 #include<cstring>
      7 #include<math.h>
      8 #include<map>
      9 #include<vector>
     10 #include<set>
     11 #include<queue>
     12 #define fori for(i=0;i<n;i++)
     13 #define fori1 for(i=1;i<=n;i++)
     14 #define inf 9999999
     15 #define Check(x,y) (x<n&&x>=0&&y>=0&&y<m)
     16 #define IOS ios::sync_with_stdio(false);cin.tie(0)
     17 #define ll long long
     18 #define inf 0x3f3f3f3f
     19 #define eps 1e-6
     20 #define pi acos(-1)
     21 #define mea (memset(a,0,sizeof(a)))
     22 #define myit set<ll>::iterator
     23 #define mysets multiset<ll>
     24 #define myits multiset<ll>::iterator
     25 #define v30 (1<<30)-1
     26 #define all(x) (x).begin(),(x).end()
     27 #define maxs *s.rbegin()
     28 #define lowbit(x) (x&(-x))
     29 #define mid ((a[k].r+a[k].l)>>1)
     30 #define lson k<<1,l,mid
     31 #define rson k<<1|1,mid+1,r
     32 #define kl k<<1
     33 #define kr k<<1|1
     34 #define ispow(n) (n & (n - 1))
     35 using namespace std;
     36 const ll N=1000005;
     37 const ll mod = 1e9 + 7;
     38 const ll de = 2e9 + 1;
     39 inline ll read() {
     40     ll s = 0, w = 1;
     41     char ch = getchar();
     42     while (ch < '0' || ch>'9') { if (ch == '-')w = -1; ch = getchar(); }
     43     while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
     44     return s * w;
     45 }
     46 void put1() { puts("YES"); }
     47 void put2() { puts("NO"); }
     48 void put3() { puts("-1"); }
     49 ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
     50 using namespace std;
     51 
     52 const int manx = 2e5 + 5;
     53 
     54 ll head[manx], d[manx], f[manx][21], lg[manx];
     55 ll k = 0;
     56 struct node {
     57     ll v, next;
     58 }e[manx * 2];
     59 void add(ll u, ll v) {
     60     e[++k].v = v;
     61     e[k].next = head[u];
     62     head[u] = k;
     63 }
     64 void dfs(ll u, ll fa) {
     65     d[u] = d[fa] + 1;
     66     f[u][0] = fa;
     67     for (int i = 1; i <= lg[d[u]]; i++)
     68         f[u][i] = f[f[u][i - 1]][i - 1];
     69     for (int i = head[u]; i; i = e[i].next)
     70         if (e[i].v != fa)
     71             dfs(e[i].v, u);
     72 }
     73 ll lca(ll a, ll b) {
     74     if (d[a] < d[b]) swap(a, b);
     75     while (d[a] > d[b]) a = f[a][lg[d[a] - d[b]] - 1];
     76     if (a == b) return a;
     77     for (int i = lg[d[a]] - 1; i >= 0; i--)
     78         if (f[a][i] != f[b][i])
     79             a = f[a][i], b = f[b][i];
     80     return f[a][0];
     81 }
     82 int red[200050],blue[200050];
     83 int main()
     84 {
     85     ll i, j, k;
     86     ll n, m, t;
     87     ll r, b,q;
     88     cin >> n;
     89         for (int i = 1; i < n; i++) {
     90             ll u = read(), v = read();
     91             add(u, v);
     92             add(v, u);
     93         }
     94         for (int i = 1; i <= n; i++)
     95             lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
     96         dfs(1, 0);
     97         cin >> q;
     98         while (q--)
     99         {
    100             cin >> r >> b;
    101             cin >> red[1];
    102             int rlca = red[1];
    103             for (i = 2; i <= r; i++)
    104             {
    105                 cin >> red[i];
    106                 rlca = lca(rlca, red[i]);
    107             }
    108             cin >> blue[1];
    109             int blca = blue[1];
    110             for (i = 2; i <= b; i++)
    111             {
    112                 cin >> blue[i];
    113                 blca = lca(blca, blue[i]);
    114             }
    115             int zonglca = lca(rlca, blca);
    116             if (rlca != zonglca && blca != zonglca)
    117             {
    118                 cout << "YES" << endl;
    119             }
    120             else if (rlca == zonglca)
    121             {
    122                 int flag = 0;
    123                 for ( i = 1; i <= r; i++)
    124                 {
    125                     if (lca(red[i], blca) == blca)
    126                     {
    127                         cout << "NO" << endl;
    128                         flag = 1;
    129                         break;
    130                     }
    131                 }
    132                 if (!flag)
    133                     cout << "YES" << endl;
    134             }
    135             else if (blca == zonglca)
    136             {
    137                 int flag = 0;
    138                 for (i = 1; i <= b; i++)
    139                 {
    140                     if (lca(blue[i], rlca) == rlca)
    141                     {
    142                         cout << "NO" << endl;
    143                         flag = 1;
    144                         break;
    145                     }
    146                 }
    147                 if (!flag)
    148                     cout << "YES" << endl;
    149             }
    150         }
    151 
    152 }

    E - Third-Party Software - 2  Gym - 102215E 

    题意:求用最少的线段覆盖整个区间,并且输出你用的线段

    思路:贪心,排序左端点从小到大,若左端点相同则取右端点从大到小排序,然后遍历即可。

    献上代码

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<vector>
     4 #include<map>
     5 #include<cstring>
     6 using namespace std;
     7 #define ll long long
     8 const int N = 2e5+5;
     9 const int mod = 1e9 + 7;
    10 struct node {
    11     ll l, r;
    12     ll id;
    13 }s[N];
    14 bool cmp(const node& a, const node& b)
    15 {
    16     if (a.l == b.l)return a.r > b.r;
    17     return a.l < b.l;
    18 }
    19 vector<ll>G;
    20 int main()
    21 {
    22     ll i, j, k;
    23     ll  n,m, t;
    24     cin >> n >> m;
    25     for (i = 0; i < n; i++)
    26     {
    27         cin >> s[i].l >> s[i].r;
    28         s[i].id = i;
    29     }
    30     sort(s, s + n, cmp);
    31     ll now = 1, ans = 0;
    32     i = 0;
    33     while (i <= n && now <= m)
    34     {
    35         ll maxn = 0;
    36         k = 0;
    37         while (i <= n && s[i].l <= now)
    38         {
    39             if (s[i].r > maxn)
    40             {
    41                 maxn = s[i].r;
    42                 k = i;
    43             }
    44             i++;
    45         }
    46         if (maxn <= now - 1)
    47         {
    48             ans = -1;
    49             break;
    50         }
    51         G.push_back(s[k].id+1);
    52         now = maxn + 1;
    53         ans++;
    54     }
    55     if (now <= m)//不能包括所有点
    56         ans = -1;
    57     if (ans == -1)
    58         cout << "NO" << endl;
    59     else
    60     {
    61         cout << "YES" << endl;
    62         cout << ans << endl;
    63         for (i = 0; i < ans; i++)
    64             cout << G[i] << " ";
    65     }
    66     
    67    
    68 
    69 }

    F - The Power of the Dark Side - 2    Gym - 102215J 

    题意:给你n个野蛮人(绝地武士)能力值a,b,c,两个武士决斗时谁有两个值大于对方谁就是胜者(a和a比,b和b比,c和c比,所有武士的三个值都不相同),现在可以交换任意武士的三个能力值位置,问有些可以击败其余所有武士。

    思路:贪心排序能力,先将自己能力进行排序,然后将打败下限(即最小能力+1和次小能力+1)进行排序,再二分upper_bound属个数,再判断有没有自己揍自己就行。

    献上代码(我提交的MV c++2017才不T)

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<vector>
     4 #include<map>
     5 #include<cstring>
     6 using namespace std;
     7 #define ll long long
     8 const int N = 5e5+25;
     9 const int mod = 1e9 + 7;
    10 ll s[N][3];
    11 ll sum[N];
    12 int i, j, k;
    13 ll  n,m, t;
    14 vector<ll>v;
    15 vector<int>ans;
    16 int main()
    17 {
    18     
    19     scanf("%d", &n);
    20     for (i = 1; i <= n; i++)
    21     {
    22         cin >> s[i][0] >> s[i][1] >> s[i][2];
    23         sum[i] = s[i][0] + s[i][1] + s[i][2];
    24         sort(s[i], s[i] + 3);
    25         v.push_back(s[i][0] + s[i][1]+2);//注意,+2这里是次大被打败需要加一,最小被打败也要+1
    26     }
    27     sort(v.begin(), v.end());
    28     for (i = 1; i <= n; i++)
    29     {
    30         int k = upper_bound(v.begin(), v.end(), sum[i]) - v.begin();
    31         ll t = sum[i] - (s[i][0] + s[i][1] + 2);
    32         if (t >= 0)
    33             k--;//减去我自己打自己
    34         ans.push_back(k);
    35     }
    36     for (i = 0; i < n; i++)
    37         printf("%d ", ans[i]);
    38 }

    G - Bashar and the bad land (Hard) Gym - 102397E

    题意:给你一个n个数和x,问最短的区间和大于等于x

    思路:前缀和+尺取法,在1点先弄一个长度(假设为R)刚好区间和大于等于x,然后从R点向右移动,然后1点一直尺取收缩使得刚好大于等于x,详情看代码吧。

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<vector>
     4 #include<cstring>
     5 using namespace std;
     6 #define ll long long
     7 const int N = 1000005;
     8 const int mod = 1e9 + 7;
     9 ll a[N],b[N],c[N];
    10 int main()
    11 {
    12     ll i, j, k;
    13     ll n, m, t,x,sum=0;
    14     cin >> n >> x;
    15     for (i = 1; i <= n; i++)
    16     {
    17         cin >> a[i];
    18         sum += a[i];
    19     }
    20     if (sum < x)
    21         cout << -1 << endl;
    22     else
    23     {
    24         a[0] = 0;
    25         for (i = 1; i <= n; i++)
    26         {
    27             b[i] = b[i - 1] + a[i];
    28         }
    29        /* for (i = 1; i <= n; i++)
    30         {
    31             cout << b[i] << " ";
    32         }*/
    33         for (i = 1; i <= n; i++)
    34             if (b[i] > x)
    35                 break;
    36        // cout << endl << i << endl;
    37         ll l = 1, r = i,ans=i,cnt=b[r];
    38         for(j=i;j<=n;j++)
    39         {
    40             cnt = b[j]-b[l-1];
    41             while (b[j] - b[l] >= x)
    42                 l++;
    43             ans = min(ans, j - l + 1);
    44            // cout << cnt << endl;
    45         }
    46         cout << ans << endl;
    47         
    48     }
    49 
    50 }

    H - Deck Sorting Gym - 102215K 

    题意:给你只含RGB的字符串,从中抽出一个子序列,和剩下的子序列拼在一起,使得拼接后的字符串相同字符在一起。

    思路:枚举6种全排列方式,比如RGB,先取全部R,G留下,然后最后一个R连接后面B,第一个G连接前面的B,若拼起来的长度不够原来的长度,则枚举下一种,直到没有符合输出NO。

    代码

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<vector>
     4 #include<map>
     5 #include<cstring>
     6 using namespace std;
     7 #define ll long long
     8 const int N = 5e5+25;
     9 const int mod = 1e9 + 7;
    10 char ju[6][3] = {
    11     {'R','G','B'},{'R','B','G'},
    12     {'G','R','B'},{'G','B','R'},
    13     {'B','G','R'},{'B','R','G'}
    14 };
    15 vector<char>s1;
    16 vector<char>s2;
    17 int main()
    18 {
    19     ll i, j, k;
    20     string s;
    21     ll n;
    22     cin >> s;
    23     n = s.size();
    24     int flag = 0;
    25     for (i = 0; i < 6; i++)
    26     {
    27         ll sum1 = 0, sum2 = 0;
    28         ll pos1 = 0, pos2 = 0;
    29         for (j = 0; j < n; j++)
    30         {
    31             if (s[j] == ju[i][0])
    32             {
    33                 sum1++;
    34                 pos1 = j;//标记最后一个点
    35             }
    36             if (s[j] == ju[i][2])
    37             {
    38                 sum2++;     
    39             }
    40         }
    41         for (j = 0; j < n; j++)
    42         {
    43             if (s[j] == ju[i][2])
    44             {
    45                 pos2 = j;//标记第一个点
    46                 break;
    47             }
    48         }
    49         for (j = 0; j < pos2; j++)
    50             if (s[j] == ju[i][1])
    51                 sum2++;
    52         for (j = n - 1; j > pos1; j--)
    53             if (s[j] == ju[i][1])
    54                 sum1++;
    55         if (sum1 + sum2 == n)
    56         {
    57             flag = 1;
    58             break;
    59         }
    60     }
    61     if (flag)
    62         cout << "YES" << endl;
    63     else
    64         cout << "NO" << endl;
    65 }
  • 相关阅读:
    spring boot 在idea中实现热部署
    spring boot jar的生成
    mongodb windows 开机启动
    使用阿里云RDS
    net core 使用ef生成实体类(SqlServer)
    在window下搭建即时即用的hyperledger fabric 的环境
    NET实现谷歌OCR的使用记录(CLOUD VISION API)
    kali 系列学习12-使用Wifite破解无线网络
    kali 系列学习10-渗透攻击MySQL数据库服务、PostgreSQL数据库服务、Tomcat服务和PDF文件
    kali 系列学习09-Kali-linux设置ProxyChains
  • 原文地址:https://www.cnblogs.com/ch-hui/p/12767416.html
Copyright © 2011-2022 走看看