A. Reverse and Concatenate

题意

给一个长度为n的字符串和k次操作,每次操作可以将原字符串 s的倒置 rev(s) 加到s后面或者s前面,

问在k次操作过后能得到几种不同的字符串

思路

经过一次操作后,必然成为回文串。对回文串进行操作就不会生成新的种类了。

只需要判断最开始的是不是回文就行了。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
 #include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
#include <math.h>
#include <queue>
#include <deque>

using namespace std;
typedef pair<int,int> PII;
const int N=1010;
string a,b;
int n,k;
int main(){
int t;
cin>>t;
while(t--){
scanf("%d%d",&n,&k);
cin>>a;
if(k==0){
printf("1\n");
continue;
}
int flg=1;
for(int i=0;i<n;i++){
if(a[i]!=a[n-i-1]){
flg=0;
break;
}
}
if(flg){
printf("1\n");
}else{
printf("2\n");
}
}
return 0;
}

B. Fortune Telling

题意

给定长度为n的数组d和初始的数字x和最后得到的数字y,Alice拿着数字x而Bob拿着数字x + 3,他们会按照数组下标从小到大的顺序给x变化,每次可以选择 x=x+d[i] 或者 x=x xor d[i]

给出最后得到的数字y,问是由哪个人的最初数字得到的

保证Alice和Bob有且仅有一个人可以得到最后的y。

思路

加上或者异或上一个奇数,改变奇偶性质。

加上或者异或上一个偶数,不改变奇偶性质。

Alice的 X 和 Bob 的 X+3 奇偶性不同

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
#include <math.h>
#include <queue>
#include <deque>

using namespace std;
typedef pair<int,int> PII;
const int N=1010;
long long aa;
long long x,y,n;
int main(){
int t;
cin>>t;
while(t--){
scanf("%lld%lld%lld",&n,&x,&y);
int cg=0;
for(int i=0;i<n;i++){
scanf("%lld",&aa);
if(aa%2){
cg++;
}
}
if((x+cg)%2==y%2){
printf("Alice\n");
}else{
printf("Bob\n");
}
}
return 0;
}

C. OKEA

题意

给定一个大小为 $n∗k$的二维数组a的全排列(数组元素从1到n),一共n行,每行k个,问是否存在这么一个排列,对于每行来说,设为 i 行,不存在任何一组 $[l,r]$, 使得 $(a[i][l]+a[i][l+1]+…+a[i][r])/(r−l+1)$为小数,输出这个排列

思路

k==1,显然存在

k>=2时,每行任意相邻两个元素必须同奇偶,因此每行所有元素同奇偶

k>=2时,n必须为偶数,否则必然存在一行,不同奇偶

注意到只要每行满足等差数列,且奇偶一致,就满足整除的要求,所以直接构造即可

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
#include <math.h>
#include <queue>
#include <deque>

using namespace std;
typedef pair<int,int> PII;
const int N=1010;

int main(){
int t,n,k;
cin>>t;
while(t--){
scanf("%d%d",&n,&k);
if(k==1){
printf("YES\n");
for(int i=1;i<=n;i++){
printf("%d\n",i);
}
continue;
}else{
if((n*k)%2){
printf("NO\n");
continue;
}else{
if(n%2){
printf("NO\n");
continue;
}else{
printf("YES\n");
for(int j=1,i=1;i<=n*k;j++,i+=2){
printf("%d ",i);
if(j%k==0) printf("\n");
}
for(int j=1,i=2;i<=n*k;j++,i+=2){
printf("%d ",i);
if(j%k==0) printf("\n");
}
continue;
}
}
}
}

return 0;
}

D. Finding Zero

题意

交互题,有一个长度为n的非负数组a,有且仅有一个0存在于这个数组中。

每次可以询问下标为i,j,k的数的极差:$max(a[i],a[j],a[k])−min(a[i],a[j],a[k])$,在至多 2n−2次的询问中找出最有可能为0的两个下标。

思路

首先我们想一个子问题,如果当前的数为4个,应该怎么做

我们设这个数组为a,且设 q(i)
表示除了对 a[i]
以外的三个数进行询问的结果,设a为单调递增的数组,a[1]==0,则

q(1)=a[4]−a[2]

q(2)=a[4]

q(3)=a[4]

q(4)=a[3]

容易得到最大的两个数一定不是0,那么对于任意的4个数,都可以排除掉两个数

当n为偶数的时候,容易得到需要询问 2n−4 次

当n为奇数的时候,容易得到需要询问 2n−2次

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <bits/stdc++.h>

#define all(x) (x).begin(), (x).end()
#define len(x) (int) (x).size()

using namespace std;


int get(const vector <int>& x) {
cout << "? " << x[0] + 1 << " " << x[1] + 1 << " " << x[2] + 1 << endl;
int ans;
cin >> ans;
return ans;
}


signed main() {
ios_base::sync_with_stdio();
cin.tie(nullptr);

int t;
cin >> t;

while(t --> 0) {
int n;
cin >> n;

pair <int, int> possible = {0, 1};
for (int i = 2; i < n - 1; i += 2) {
vector <pair <int, int>> ch(4);
vector <int> now = {possible.first, possible.second, i, i + 1};
for (int j = 0; j < 4; j++) {
vector <int> x = now;
x.erase(x.begin() + j);
ch[j] = {get(x), now[j]};
}
sort(all(ch));
possible = {ch[0].second, ch[1].second};
}
if (n % 2 == 1) {
int other = 0;
while (possible.first == other || possible.second == other) {
other++;
}
vector <pair <int, int>> ch(4);
vector <int> now = {possible.first, possible.second, n - 1, other};
for (int j = 0; j < 4; j++) {
vector <int> x = now;
x.erase(x.begin() + j);
ch[j] = {get(x), now[j]};
}
sort(all(ch));
possible = {ch[0].second, ch[1].second};
}
cout << "! " << possible.first + 1 << " " << possible.second + 1 << endl;
}

return 0;
}

E - Fair Share

题意

给定m个一维数组,每个数组长度随机

将所有元素分到两个集合A、B中去,判断是否存在一个方案使得:

1、对于每个一维数组,分到A的元素个数和分到B的元素个数相等

2、集合A与集合B相同

思路

首先所有的数字必须出现偶数次

构造一个二分图$$:

$V_1$ : m个数组 $V_2$ : 所有出现的数字$n_i$

如果数字 $x$ 出现到了第 $i$ 个数组中,就连一条边。

问题转换为求该二部图的欧拉通路

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <bits/stdc++.h>

#define len(x) (int) (x).size()
#define all(x) (x).begin(), (x).end()
#define endl "\n"

using namespace std;

const int N = 4e5 + 100, H = 2e5 + 50;
vector <pair <int, int>> g[N];
string ans[N];
int pos[N];


void dfs(int v) {
if (pos[v] == 0) {
ans[v] = string(len(g[v]), 'L');
}

while (pos[v] < len(g[v])) {
auto [i, ind] = g[v][pos[v]];
if (i == -1) {
pos[v]++;
continue;
}
g[i][ind].first = -1, g[v][pos[v]].first = -1;
if (v < H) {
ans[v][pos[v]] = 'R';
}
pos[v]++;
dfs(i);
}
}


signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);

int m;
cin >> m;
map <int, int> ind, cnt;
int fre_ind = 0;

vector <vector <int>> nums(m);
for (int i = 0; i < m; i++) {
int n;
cin >> n;
for (int _ = 0; _ < n; _++) {
int x;
cin >> x;
if (!ind.count(x)) {
ind[x] = fre_ind++;
}
x = ind[x];
cnt[x]++;
nums[i].push_back(x);
g[i].emplace_back(x + H, len(g[x + H]));
g[x + H].emplace_back(i, len(g[i]) - 1);
}
}

for (auto [num, cn] : cnt) {
if (cn % 2 == 1) {
cout << "NO" << endl;
return 0;
}
}

for (int i = 0; i < N; i++) {
dfs(i);
}

cout << "YES" << endl;
for (int i = 0; i < m; i++) {
cout << ans[i] << endl;
}
return 0;
}