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", 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\n", 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\n", (int)v.size());
23     for (auto &i : v)
24         printf("%d ", i);
25     printf("\n");
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\n"), 0;
43     }
44     for (int i = 1; i <= n; ++i)
45         printf("%d%c", b[i], " \n"[i == n]);
46     return 0;
47 }
View Code

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

*D、Ehab's Last Corollary

题意:

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

题解:

找环是比较简单的,所以考虑先找环。然后注意到:如果找到的最小环都比$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\n%d\n", dep[u] - dep[i] + 1);
24                 for (int j = dep[i] - 1; j < dep[u]; ++j)
25                     printf("%d%c", cyc[j], " \n"[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\n");
47     for (int i = 1, cnt = 1; i <= n && cnt <= (k + 1) / 2; ++i)
48         if (!vis[i])
49             printf("%d%c", i, " \n"[cnt == (k + 1) / 2]), ++cnt;
50     return 0;
51 }
View Code

 

posted @ 2020-06-15 21:17  Aya_Uchida  阅读(163)  评论(0编辑  收藏  举报