A. Reverse and Concatenate
思路:
答
案
要
么
1
要
么
2
答案要么1要么2
答案要么1要么2
等
于
1
的
必
要
条
件
是
反
转
之
后
是
它
本
身
等于1的必要条件是反转之后是它本身
等于1的必要条件是反转之后是它本身
反
之
就
是
2
反之就是2
反之就是2
时间复杂度:
O
n
On
On
#define sf(x) scanf("%d",&x)
#define all(x) (x).begin(),(x).end()
#define cf int _; cin>> _; while(_--)
inline void sf2(int &a , int &b) { sf(a) , sf(b) ;}
signed main()
{
cf
{
int n , m ;
sf2(n, m);
string s;
cin >> s;
string ans = s;
reverse(all(s));
if (s != ans && m)
puts("2");
else
puts("1");
}
return 0;
}
B. Fortune Telling
思路:
注
意
到
x
和
x
+
3
奇
偶
性
不
同
注意到x和x+3奇偶性不同
注意到x和x+3奇偶性不同
如
果
a
是
奇
数
,
b
是
偶
数
如果a是奇数,b是偶数
如果a是奇数,b是偶数
假
设
x
是
奇
数
假设x是奇数
假设x是奇数
a
+
=
x
是
偶
数
a+=x是偶数
a+=x是偶数
b
+
=
x
是
奇
数
b+=x是奇数
b+=x是奇数
a
⊕
=
x
是
偶
数
a\oplus=x是偶数
a⊕=x是偶数
b
⊕
=
x
是
奇
数
b\oplus=x是奇数
b⊕=x是奇数
x
是
偶
数
同
理
x是偶数同理
x是偶数同理
我
们
发
现
a
和
b
的
奇
偶
性
一
直
是
相
对
的
我们发现a和b的奇偶性一直是相对的
我们发现a和b的奇偶性一直是相对的
如
果
x
是
偶
数
a
b
奇
偶
性
不
变
如果x是偶数ab奇偶性不变
如果x是偶数ab奇偶性不变
如
果
x
是
奇
数
a
b
奇
偶
性
交
换
如果x是奇数ab奇偶性交换
如果x是奇数ab奇偶性交换
题
目
最
后
一
句
话
题目最后一句话
题目最后一句话
exactly one of your friends could have actually gotten that number.
说
明
答
案
必
定
存
在
说明答案必定存在
说明答案必定存在
所
以
统
计
奇
数
个
数
即
可
所以统计奇数个数即可
所以统计奇数个数即可
说
点
题
外
话
,
奇
偶
性
这
个
性
质
c
f
经
常
考
,
可
以
多
做
做
类
似
的
题
说点题外话,奇偶性这个性质cf经常考,可以多做做类似的题
说点题外话,奇偶性这个性质cf经常考,可以多做做类似的题
时间复杂度:
O
n
On
On
#define fer(i,a,b) for(int i = a ; i <= b ; ++ i)
#define cf int _; cin>> _; while(_--)
const int N = 1e6 + 10 ;
int n ;
int a[N] , x , y ;
signed main()
{
cf
{
cin >> n >> x >> y ;
int cnt = 0 ;
fer(i,1,n)
{
sf(a[i]) ;
if(a[i] & 1) cnt ++ ;
}
if(x & 1)
{
if(y & 1)
{
if(cnt % 2 == 0) puts("Alice") ;
else puts("Bob") ;
}
else
{
if(cnt % 2) puts("Alice") ;
else puts("Bob") ;
}
}
else
{
if(y & 1)
{
if(cnt % 2 == 0) puts("Bob") ;
else puts("Alice") ;
}
else
{
if(cnt % 2) puts("Bob") ;
else puts("Alice") ;
}
}
}
return 0;
}
C. OKEA
思路:
n
是
偶
数
或
者
k
<
=
1
可
以
,
否
则
都
不
可
以
n是偶数或者k<=1可以,否则都不可以
n是偶数或者k<=1可以,否则都不可以
时间复杂度:
O
n
k
Onk
Onk
#define fer(i,a,b) for(int i = a ; i <= b ; ++ i)
#define cf int _; cin>> _; while(_--)
signed main()
{
cf
{
int n , k ;
cin >> n >> k ;
if(n % 2 == 0)
{
puts("YES") ;
int cnt = 0 ;
for(int i = 1 ; i <= n * k ; i += 2)
{
cnt ++ ;
cout << i << " " ;
if(cnt == k)
{
cnt = 0 ;
puts("") ;
}
}
for(int i = 2 ; i <= n * k ; i += 2)
{
cnt ++ ;
cout << i << " " ;
if(cnt == k)
{
cnt = 0 ;
puts("") ;
}
}
}
else if(k <= 1)
{
puts("YES") ;
if(k == 1)
{
fer(i,1,n*k)
{
cout << i << "\n" ;
}
}
}
else puts("NO") ;
}
return 0;
}
D. Finding Zero
思路:
没
错
,
d
题
想
了
快
2
h
才
做
出
来
没错,d题想了快2h才做出来
没错,d题想了快2h才做出来
有
个
超
级
超
级
重
要
的
性
质
有个超级超级重要的性质
有个超级超级重要的性质
经
过
了
漫
长
时
间
的
思
考
以
及
草
稿
纸
上
的
举
不
出
反
例
才
得
到
的
结
果
经过了漫长时间的思考以及草稿纸上的举不出反例才得到的结果
经过了漫长时间的思考以及草稿纸上的举不出反例才得到的结果
第 一 次 假 设 三 个 数 a [ x ] , a [ y ] , a [ z ] 的 下 标 是 1 , 2 , 3 第一次假设三个数a[x],a[y],a[z]的下标是1,2,3 第一次假设三个数a[x],a[y],a[z]的下标是1,2,3
假
设
当
前
差
值
为
l
a
s
t
假设当前差值为last
假设当前差值为last
差
值
就
是
最
大
值
−
最
小
值
,
也
就
是
询
问
x
,
y
,
z
的
结
果
差值就是最大值-最小值,也就是询问x,y,z的结果
差值就是最大值−最小值,也就是询问x,y,z的结果
做
2
次
循
环
做2次循环
做2次循环
第
一
次
用
4
到
n
的
每
一
个
数
去
替
换
掉
第
三
个
数
第一次用4到n的每一个数去替换掉第三个数
第一次用4到n的每一个数去替换掉第三个数
如
果
当
前
差
值
大
于
等
于
>
=
l
a
s
t
如果当前差值大于等于>=last
如果当前差值大于等于>=last
就
替
换
掉
第
三
个
数
,
同
时
更
新
l
a
s
t
=
当
前
差
值
,
否
则
不
替
换
就替换掉第三个数,同时更新last=当前差值,否则不替换
就替换掉第三个数,同时更新last=当前差值,否则不替换
同
理
,
第
二
次
循
环
替
换
掉
第
二
个
数
同理,第二次循环替换掉第二个数
同理,第二次循环替换掉第二个数
同
时
更
新
l
a
s
t
同时更新last
同时更新last
两
次
循
环
之
后
,
a
[
x
]
,
a
[
y
]
,
a
[
z
]
必
定
存
在
0
和
当
前
数
组
中
的
最
大
值
两次循环之后,a[x],a[y],a[z]必定存在0和当前数组中的最大值
两次循环之后,a[x],a[y],a[z]必定存在0和当前数组中的最大值
那
怎
么
找
到
0
和
最
大
值
呢
那怎么找到0和最大值呢
那怎么找到0和最大值呢
有
个
逻
辑
是
这
样
的
,
你
找
另
外
一
个
下
标
i
d
有个逻辑是这样的,你找另外一个下标id
有个逻辑是这样的,你找另外一个下标id
询
问
i
d
,
y
,
z
的
结
果
询问id,y,z的结果
询问id,y,z的结果
如
果
当
前
差
值
=
l
a
s
t
,
说
明
a
[
x
]
一
定
不
是
0
,
那
么
输
出
y
,
z
即
可
如果当前差值=last,说明a[x]一定不是0,那么输出y,z即可
如果当前差值=last,说明a[x]一定不是0,那么输出y,z即可
同 理 当 前 差 值 ! = l a s t , 那 就 用 i d 替 换 y / z 同理当前差值!=last,那就用id替换y/z 同理当前差值!=last,那就用id替换y/z
题
外
话
题外话
题外话
一
开
始
的
三
个
数
的
下
标
不
一
定
非
得
是
1
,
2
,
3
,
任
意
三
个
不
同
的
下
标
都
可
一开始的三个数的下标不一定非得是1,2,3,任意三个不同的下标都可
一开始的三个数的下标不一定非得是1,2,3,任意三个不同的下标都可
两
次
循
环
不
一
定
非
得
替
换
第
二
个
数
和
第
三
个
数
,
任
意
2
个
数
皆
可
两次循环不一定非得替换第二个数和第三个数,任意2个数皆可
两次循环不一定非得替换第二个数和第三个数,任意2个数皆可
这
个
性
质
可
以
在
草
稿
纸
上
仔
细
想
想
推
敲
推
敲
这个性质可以在草稿纸上仔细想想推敲推敲
这个性质可以在草稿纸上仔细想想推敲推敲
个
人
觉
得
举
不
出
来
反
例
在
算
法
竞
赛
当
中
往
往
是
较
为
正
确
的
证
明
个人觉得举不出来反例在算法竞赛当中往往是较为正确的证明
个人觉得举不出来反例在算法竞赛当中往往是较为正确的证明
时间复杂度:
O
n
2
On^2
On2
#define cf int _; cin>> _; while(_--)
signed main()
{
cf
{
int n ;
cin >> n ;
int x = 1 , y = 2 , z = 3 ;
int last ;
cout << "? " << x << " " << y << " " << z << '\n' ;
cout.flush() ;
cin >> last ;
for(int i = 4 ; i <= n ; i ++)
{
cout << "? " << x << " " << y << " " << i << '\n' ;
cout.flush() ;
int k ;
cin >> k ;
if(k >= last)
{
last = k ;
z = i ;
}
}
for(int i = 1 ; i <= n ; i ++)
{
if(i == x || i == y || i == z) continue ;
cout << "? " << x << " " << i << " " << z << '\n' ;
cout.flush() ;
int k ;
cin >> k ;
if(k >= last)
{
last = k ;
y = i ;
}
}
int id = -1 ;
for(int i = 1 ; i <= n ; i ++)
{
if(i == x || i == y || i == z) continue ;
id = i ;
break ;
}
int k ;
cout << "? " << id << " " << y << " " << z << '\n' ;
cout.flush() ;
cin >> k ;
if(k == last)
{
cout << "! " << y << " " << z << "\n" ;
}
else
{
cout << "? " << x << " " << id << " " << z << '\n' ;
cout.flush() ;
cin >> k ;
if(k == last)
{
cout << "! " << x << " " << z << "\n" ;
}
else
{
cout << "? " << x << " " << y << " " << id << '\n' ;
cout.flush() ;
cin >> k ;
if(k == last)
{
cout << "! " << x << " " << y << "\n" ;
}
else cout << "! " << x << " " << y << "\n" ;
}
}
}
return 0;
}