题目链接
A. Windblume Ode
题意
- 给我们一个长度为 n 的数组 a,a 中元素个不相同,让我们从中选择尽可能多的数,形成一个子集,要求这个子集中的所有数字和为一个非质数。输出这个最大尺寸。
思路
- 当 a 中所有的元素和不为质数时,选择 a 中的所有元素。
- 当 a 中所有元素和为质数的时候,我们只需要去掉以一个奇数,就行了,因为质数一定是奇数,所有 a 中一定存在奇数。
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
const int N = 1e5 + 10;
int n, m;
int a[N];
int main()
{
int T; scanf("%d", &T);
while (T --)
{
scanf("%d", &n);
int sum = 0;
for (int i = 1; i <= n; i ++) {
scanf("%d", &a[i]);
sum += a[i];
}
int flag = 0;
for (int i = 2; i <= sum / i; i ++) {
if (sum % i == 0)
{
flag = 1;
}
}
if (flag)
{
printf("%d\n", n);
for (int i = 1; i <= n; i ++) printf("%d ", i);
}
else
{
printf("%d\n", n - 1);
for (int i = 1; i <= n; i ++)
{
if (flag == 0 && a[i] % 2)
flag = 1;
else
printf("%d ", i);
}
}
printf("\n");
}
return 0;
}
B. Omkar and Heavenly Tree
题意
- 让我们构造一颗 n 个节点的树,但是要满足 m 个限制条件,
- 第 i 个限制条件为 a i b i c i ai~~bi~~ci ai bi ci, 表示 ai 到 ci 的简单路径中不能有 bi 这个节点。
思路
- 把所有有限制的节点 bi 标记一下,然后找一个没有被标记的节点作为 root,然后把 root 与剩下点连边就可以了。
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
const int N = 1e5 + 10;
int n, m;
int mk[N];
int main()
{
int T; scanf("%d", &T);
while (T --)
{
scanf("%d %d", &n, &m);
int a, b, c;
for (int i = 1; i <= n; i ++) mk[i] = 0;
while (m --)
{
scanf("%d %d %d", &a, &b, &c);
mk[b] = 1;
}
int x = 0;
for (int i = 1; i <= n; i ++) {
if (mk[i] == 0)
{
x = i;
break;
}
}
for (int i = 1; i <= n; i ++) {
if (i != x)
{
printf("%d %d\n", x, i);
}
}
}
return 0;
}
C. Omkar and Determination
题意
- 一道阅读理解题,自己看题意吧。
思路
- 对于每个询问我们需要判读所求的子矩阵,是否是 yes,要判断这个子矩阵中处理第一行和第一列之外的其他点,是否能向左或向上走到一个空地‘.’ ,如果都满足的话就可以,
- 我们只需要预处理 + 前缀和搞一搞就行了 。
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
const int N = 1e6 + 10;
int n, m;
vector<char> a[N];
int ok[N], sum[N];
int main()
{
scanf("%d %d ", &n, &m);
for (int i = 1; i <= n; i ++) {
a[i].resize(m + 1);
for (int j = 1; j <= m; j ++) {
scanf("%c", &a[i][j]);
}
getchar();
}
for (int j = 2; j <= m; j ++) {
ok[j] = 1;
for (int i = 2; i <= n; i ++) {
if (a[i - 1][j] == 'X' && a[i][j - 1] == 'X')
{
ok[j] = 0;
break;
}
}
}
for (int i = 1; i <= m; i ++)
sum[i] = sum[i - 1] + ok[i];
int q; scanf("%d", &q);
int x, y;
while (q --)
{
scanf("%d %d", &x, &y);
if (sum[y] - sum[x] == y - x)
{
printf("YES\n");
}
else
{
printf("NO\n");
}
}
return 0;
}
D. Omkar and the Meaning of Life
题意
- 交互题,现在我们要求一个排列数组 p [] , 我们每次可以输出一个自己构造的 a [] 数组,
- 然后系统会形成一个 c [] 数组, ci = ai + pi, 之后系统会返回一个 k,表示 c [k] 这个数字在 c 中出现的次数最多。如果有多个最大值输出最早的那个位置。如果出现的最大的那个次数才为 1,那么返回一个 0.
思路
- 这题我们可以通过询问求出相对关系,
- 首先询问分两部分
-
第一部分:询问 n-1 次,第 i 次把 1~n-1 的值置为 i+1, 把 n 位置 的值设为 1,这样返回过来的 k 表示比 p [n] 小的数的下标。
-
第一部分:询问 n-1 次,第 i 次把 1~n-1 的值置为 1, 把 n 位置 的值设为 i+1,这样返回过来的 k 表示比 p [n] 大的数的下标。
-
- 有了上两步的分的情况,我们就可以知道 他们之间的相对关系了,之后再求个偏移量就可以了。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int a[N];
int main()
{
int n, k, mx = 0; //a[i] 里面存储的是相对大小,mx 为偏移量,把相对大小都偏移 mx+1 为就是真实的数字了
cin >> n;
for (int i = 2; i <= n; i ++) {
cout << '?';
for (int j = 1; j < n; j ++) cout << " " << i;
cout << " " << 1 << endl;
cin >> k;
a[k] = - (i - 1);
if (k > 0) mx = max(i - 1, mx);
}
for (int i = 2; i <= n; i ++) {
cout << '?';
for (int j = 1; j < n; j ++) cout << " " << 1;
cout << " " << i << endl;
cin >> k;
a[k] = i - 1;
}
cout << '!';
for (int i = 1; i <= n; i ++) cout << " " << a[i] + mx + 1;
return 0;
}