Codeforces Round #803 (Div. 2)https://codeforces.com/contest/1698
A. XOR Mixup
如果能把n-1的值xor变成最后一个值,那么所有的值xor一下=0,而相等的数xor=0,也就是说所有的数都能当最后一个数
#include<bits/stdc++.h>
using namespace std;
#define endl '\n';
#define DE printf("!");
const int maxn = 1e6+10;
int num[maxn];
int qian[maxn];
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while(t--){
int n;
cin>>n;
for(int i = 1;i<=n;i++)
cin>>num[i];
cout<<num[n]<<endl;
}
}
//直接模拟试试
//只要后面的数能满足被m分解的条件,就可能后面的数分解后再和前面的数相合成
B. Rising Sand
k=1的时候,很明显,从2-n-1挑选间隔为1的数进行增大就行,k>=2的时候,不管怎么操作都会影响至少一个相邻的数,所以k>=2的时候不操作得到的答案就是最多的
#include<bits/stdc++.h>
using namespace std;
#define endl '\n';
#define DE printf("!");
const int maxn = 1e6+10;
int num[maxn];
int qian[maxn];
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while(t--){
int n,k;
cin>>n>>k;
for(int i = 1;i<=n;i++)
cin>>num[i];
if(k==1){
cout<<(n-2)/2+n%2<<endl;
}
else{
int ans = 0;
for(int i = 2;i<n;i++){
if(num[i]>num[i-1]+num[i+1])
ans++;
}
cout<<ans<<endl;
}
}
}
//k=1的时候,间隔有最大
//k>=2的时候,想增大某个数必然同时增大相邻的某个数
C. 3SUM Closure
从构造这些数字的角度反向考虑一下,如果有三个同号的数,就会存在一个无限生成的情况,a1+a2+a3 = a4,然后a4+a2+a3 = a5这样无限生成下去,因此是不可能的。然后两个同号带0也是一样,会无限生成数字。比如1+2+0 = 3,然后3+1+2 = 6.。。这样就无限生成了,因此是不存在的。然后我们考虑几种可能的情况,第一种是全0,第二种是只有一个正数/负数和其他0,第三种是一正一负但是一定要和为0,然后带上其他0,第四种是不带0的时候两正一负/两负一正/两负两正,第四种情况因为不带0,所以n是3/3/4这样,直接暴力判断就好了。然后第一种第二种第三种统计一下正数负数个数和总和判断即可
#include<bits/stdc++.h>
using namespace std;
#define endl '\n';
#define DE printf("!");
const int maxn = 1e6+10;
int num[maxn];
int qian[maxn];
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while(t--){
int n;
cin>>n;
map<int,int>m;
for(int i = 1;i<=n;i++)
cin>>num[i];
int znum = 0,fnum = 0;
for(int i = 1;i<=n;i++){
if(num[i]>0)
znum++;
if(num[i]<0)
fnum++;
m[num[i]]++;
}
int j = 0;
if(n<=4){
int jj = 1;
for(int i = 1;i<=n-2;i++)
for(int k = i+1;k<=n-1;k++)
for(int l = k+1;l<=n;l++){
if(!m.count(num[i]+num[k]+num[l])){
//cout<<i<<" "<<k<<" "<<l<<endl;
jj = 0;
break;
}
}
//cout<<num[1]+num[2]+num[3]<<" "<<m.count(num[1]+num[2]+num[3])<<" "<<jj;
if(jj)
j =1;
}
else{
if(fnum+znum<=1)
j = 1;
else if(fnum+znum==2){
int sum = 0;
for(int i = 1;i<=n;i++)
sum+=num[i];
if(sum==0)
j = 1;
}
}
if(j==1){
cout<<"YES"<<endl;
}
else{
cout<<"NO"<<endl;
}
}
}
//因为有可能会存在无限延伸出去的情况:三个同号的,两个同号并且带0的
//因此成立的只有几种情况:全0,只有一个正数,只有一个负数
//一正一负要相加为0才行
//两正一负不能带0,同时要满足题目条件,两负一正也是
//两正两负特殊讨论
D. Fixed Point Guessing
交互题,一般都是二分,重点是搞清楚它的交换情况,不是随意排序数字,而是交换,也就是说:如果下标为i的数据为j,那么下标j的数据一定为i。这样我们就可以推导出贪心原则了,就是如果我们询问l-r的数据中,存在奇数个大小在l-r中的数据,那么答案一定在l-r中。原理是,我们可以想一下,l-r的数交换有两种选择,一种是和l-r中不相邻的数交换,一种是和以外的数交换。如果和l-r内的交换,那么一定会在统计l-r的数据中贡献2次,如果和l-r以外的数交换,那么会贡献0次,而只有不动的那个数才会贡献一次。因此,区间含有不动的那个数的统计个数为奇数个,反之为偶数个
#include<bits/stdc++.h>
using namespace std;
#define DE printf("!");
const int maxn = 1e6+10;
int num[maxn];
int qian[maxn];
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t;
cin>>t;
while(t--){
int n,x;
cin>>n;
int l = 1,r = n;
while(l<r){
int mid = (l+r)>>1;
int cnt = 0;
cout<<"? "<<l<<" "<<mid<<endl;
for(int i = l;i<=mid;i++){
cin>>x;
if(x<=mid&&x>=l)
cnt++;
}
if(cnt&1)
r = mid;
else
l = mid+1;
}
cout<<"! "<<l<<endl;
}
}
//这种交互题一般都是二分
//注意题目,不是随意交换的,如果我们知道下标1的位置是3,那么下标3的位置一定是1
//因此,在一个区间内,如果存在偶数个在这个区间内的数字,说明都是彼此成对的,比如1-4的下标是3 4 1 2或者 3 6 1 8
//如果存在奇数个在这个区间的数字,那么那个没有交换的一定在那个区间内