zoukankan      html  css  js  c++  java
  • codeforces Round 649(div. 2)


    A、XXXXX

    题意:

    在一个数组中找出连续的一段,使得其和不能被$x$整除,且长度尽可能长。

    题解:

    显然取全部的时候长度最长,如果这个时候不行,就分别枚举其前缀和和后缀和,取两边长度最大值,如果都找不到,输出$-1$。

    AC代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 1e5 + 5;
     4 int a[N];
     5 void solve()
     6 {
     7     int n, sum = 0, x;
     8     scanf("%d%d", &n, &x);
     9     for (int i = 1; i <= n; ++i)
    10         scanf("%d", &a[i]), sum += a[i];
    11     if (sum % x)
    12     {
    13         printf("%d
    ", n);
    14         return;
    15     }
    16     int tmp = sum, i, ans = -1;
    17     for (i = 1; i <= n && tmp % x == 0; ++i)
    18         tmp -= a[i];
    19     ans = max(ans, n - i + 1);
    20     tmp = sum;
    21     for (i = n; i && tmp % x == 0; --i)
    22         tmp -= a[i];
    23     ans = max(ans, i);
    24     printf("%d
    ", ans ? ans : ans - 1);
    25 }
    26 int main()
    27 {
    28     int T;
    29     scanf("%d", &T);
    30     while (T--)
    31         solve();
    32     return 0;
    33 }
    View Code

    B、Most socially-distanced subsequence

    题意:

    给出一个排列$p$,长度为$n$,求找出一个长度为$k$序列$s$,使$|s_1-s_2|+|s_2-s_3|+...+|s_{k-1}-s_k|$尽量大,满足前面条件,还要$s$的长度尽量小。

    题解:

    对于单调的子段,只取端点处是最优的,所以取所有的山峰,山谷的点,并且必取$p[1]$和$p[n]$。

    AC代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 1e5 + 5;
     4 int a[N];
     5 vector<int> v;
     6 void solve()
     7 {
     8     int n;
     9     scanf("%d", &n);
    10     for (int i = 1; i <= n; ++i)
    11         scanf("%d", &a[i]);
    12     v.clear();
    13     v.push_back(a[1]);
    14     for (int i = 2; i < n; ++i)
    15     {
    16         if (a[i] > a[i - 1] && a[i] > a[i + 1])
    17             v.push_back(a[i]);
    18         else if (a[i] < a[i - 1] && a[i] < a[i + 1])
    19             v.push_back(a[i]);
    20     }
    21     v.push_back(a[n]);
    22     printf("%d
    ", (int)v.size());
    23     for (auto &i : v)
    24         printf("%d ", i);
    25     printf("
    ");
    26 }
    27 int main()
    28 {
    29     int T;
    30     scanf("%d", &T);
    31     while (T--)
    32         solve();
    33     return 0;
    34 }
    View Code

    *C、Ehab and Prefix MEXs

    题意:

    给出一个数组$a$,求相同长度的非负数组$b$,使得$b$中的每个元素都不大于$1e6$,且$mex(b_1,b_2,...,b_i)=a_i$。

    题解:

    自己想的时候总是往给$b$数组按顺序分配$1~n$再调整想了,然后发现好像不可做。因为这样子分配,如果有了冲突之后,修改的成本很大,会$TLE$。

    注意到$a$数组是非递降的,且$a_i leq i$,这就说明似乎可以考虑双指针?考虑在当前位置,$a_i$和$b_i$必不相同,所以我们考虑把出现在$a$数组的数,和不出现在$a$数组的数分成两组,都按升序排,分别称为$1$,组$2$,如果组$1$当前没有选完,并且$a_i>group1[pos1]$,说明当前的组$1$这个数已经在$a$中出现了(重复的话,这个位置直接填$a$中没出现过的或者无穷大($1e6$)),所以自然可以尝试填进去。然后填完之后检查可行性即可。可行性的检查就是直接遍历从$0$开始的每一个数,然后看看是不是$a_i-1$就是当前的遍历结果,如果出现一个失败,就是不存在。

    AC代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 1e5 + 5;
     4 const int INF = 1e5 + 1;
     5 int buc[N << 4];
     6 int a[N], b[N], g1[N], g2[N];
     7 int main()
     8 {
     9     int n;
    10     scanf("%d", &n);
    11     for (int i = 1; i <= n; ++i)
    12     {
    13         scanf("%d", &a[i]);
    14         ++buc[a[i]];
    15     }
    16     int cnt1 = 0, cnt2 = 0;
    17     for (int i = 0; i <= a[n]; ++i)
    18     {
    19         if (buc[i])
    20             g1[++cnt1] = i;
    21         else
    22             g2[++cnt2] = i;
    23     }
    24     int pos1 = 1, pos2 = 1;
    25     for (int i = 1; i <= n; ++i)
    26     {
    27         if (pos1 <= cnt1 && a[i] > g1[pos1])
    28             b[i] = g1[pos1++];
    29         else if (pos2 <= cnt2)
    30             b[i] = g2[pos2++];
    31         else
    32             b[i] = INF;
    33     }
    34     memset(buc, 0, sizeof(buc));
    35     int tmp = -1;
    36     for (int i = 1; i <= n; ++i)
    37     {
    38         buc[b[i]] = 1;
    39         while (buc[tmp + 1])
    40             ++tmp;
    41         if (a[i] != tmp + 1)
    42             return printf("-1
    "), 0;
    43     }
    44     for (int i = 1; i <= n; ++i)
    45         printf("%d%c", b[i], " 
    "[i == n]);
    46     return 0;
    47 }
    View Code

    注意:还是要多注意题目的条件,这样子可以找到正解的切入点。

    *D、Ehab's Last Corollary

    题意:

    给出一个图,找出一个至多有$k$个点的环或者找到一个有$lceil frac{k}{2} ceil$个点的独立集(即集中任何两个元素没有边直接相连)。

    题解:

    找环是比较简单的,所以考虑先找环。然后注意到:如果找到的最小环都比$k$大,那么只要我对这个环隔一个点输出一个点,一定能找到这个独立集。所以题目就转化成,找个环就行了。找最小环通过$dfs树$即可,考虑到图可能会变成树,但是树的$dfs树$是它本身,所以我们万一找不到适合的环,我们可以考虑如何在树上找独立集,然后推广到图的$dfs$树上。对于树的每一层的结点数一定比它的下一层的结点数少,所以我们回溯的时候把所有叶节点染白,然后白点的邻接点全部染黑,在白色的结点中找这个独立集。

    AC代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 1e5 + 5;
     4 vector<int> G[N];
     5 bool vis[N];
     6 vector<int> cyc;
     7 int dep[N];
     8 int n, m, k;
     9 void dfs(int u, int fa)
    10 {
    11     cyc.push_back(u);
    12     dep[u] = dep[fa] + 1;
    13     for (auto i : G[u])
    14     {
    15         if (i == fa)
    16             continue;
    17         if (!dep[i])
    18             dfs(i, u);
    19         else
    20         {
    21             if (dep[u] - dep[i] + 1 >= 0 && dep[u] - dep[i] + 1 <= k)
    22             {
    23                 printf("2
    %d
    ", dep[u] - dep[i] + 1);
    24                 for (int j = dep[i] - 1; j < dep[u]; ++j)
    25                     printf("%d%c", cyc[j], " 
    "[j == dep[u] - 1]);
    26                 exit(0);
    27             }
    28         }
    29     }
    30     if (!vis[u])
    31         for (auto i : G[u])
    32             vis[i] = 1;
    33     cyc.pop_back();
    34 }
    35 int main()
    36 {
    37     scanf("%d%d%d", &n, &m, &k);
    38     for (int i = 1; i <= m; ++i)
    39     {
    40         int u, v;
    41         scanf("%d%d", &u, &v);
    42         G[u].push_back(v);
    43         G[v].push_back(u);
    44     }
    45     dfs(1, 0);
    46     printf("1
    ");
    47     for (int i = 1, cnt = 1; i <= n && cnt <= (k + 1) / 2; ++i)
    48         if (!vis[i])
    49             printf("%d%c", i, " 
    "[cnt == (k + 1) / 2]), ++cnt;
    50     return 0;
    51 }
    View Code
  • 相关阅读:
    bzoj 3438: 小M的作物
    bzoj 4445 [SCOI2015] 小凸想跑步
    hdu 4899 Hero meet devil
    hdu 4898 The Revenge of the Princess’ Knight
    【NOIP1999】拦截导弹
    【OpenJudge】2991:2011 题解
    【cqbzoj】1785:残缺棋盘上放车的方案数 --状压dp --输入毁一生
    【cqbzoj】:1330 Prime DP(Ahio2001 质数和分解)
    【Openjudge:Noi】7891:一元三次方程求解 c++
    【USACO FEB 2010 SILVER】吃巧克力(Chocolate Eating)
  • 原文地址:https://www.cnblogs.com/Aya-Uchida/p/13134885.html
Copyright © 2011-2022 走看看