CF1991
A. Maximize the Last Element
很明显只有奇数项可以留到最后,所以取奇数项的max即可
#include<bits/stdc++.h>
using namespace std;
int t,n,a[105];
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
int res=0;
for(int i=1;i<=n;i+=2)res=max(res,a[i]);
printf("%d\n",res);
}
return 0;
}
B. AND Reconstruction
看到位运算先考虑按位做,如果 \(b_i\) 的某一位为 \(1\) , 那么 \(a_i\) 和 \(a_{i+1}\) 的那一位都为 \(1\) 其他位为 \(0\) 即可
最后检验一遍是否符合
#include<bits/stdc++.h>
using namespace std;
int t,n,a[100005],b[100005];
bool vis[100005];
void init(){
for(int i=1;i<=n;i++)a[i]=0;
}
bool check(){
for(int i=1;i<n;i++)
if((a[i]&a[i+1])!=b[i])
return 1;
return 0;
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<n;i++)scanf("%d",&b[i]);
for(int i=0;i<30;i++){
for(int j=1;j<n;j++)
if((b[j]>>i)&1)
vis[j]=vis[j+1]=1;
for(int j=1;j<=n;j++){
if(vis[j])a[j]^=(1<<i);
vis[j]=0;
}
}
if(check())puts("-1");
else{
for(int i=1;i<=n;i++)printf("%d ",a[i]);
puts("");
}
init();
}
return 0;
}
C. Absolute Zero
直接每次 \(x=(mx+mn)/2\) 就行
这样每次操作以后极差都/2
#include<bits/stdc++.h>
using namespace std;
int t,n,a[200005],res[45],tot;
bool check(){
for(int i=1;i<=n;i++)
if(a[i])
return 0;
return 1;
}
int main(){
scanf("%d",&t);
while(t--){
tot=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=40;i++){
sort(a+1,a+1+n);
int x=(a[1]+a[n])/2;
for(int i=1;i<=n;i++)a[i]=abs(a[i]-x);
res[++tot]=x;
if(check())break;
}
if(check()){
printf("%d\n",tot);
for(int i=1;i<=tot;i++)printf("%d ",res[i]);
puts("");
}else puts("-1");
}
return 0;
}
D. Prime XOR Coloring
一开始看到一堆人秒过直接交了个 \(n/2+1\) , 唐死了
根据样例后面至少分4个颜色
所以按照mod4的余数分个类就行,这样同种颜色异或结果总会是4的倍数
#include<bits/stdc++.h>
using namespace std;
int t,n;
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
if(n==1)puts("1\n1");
else if(n==2)puts("2\n1 2");
else if(n==3)puts("2\n1 2 2");
else if(n==4)puts("3\n1 2 2 3");
else if(n==5)puts("3\n1 2 2 3 3");
else{
printf("%d\n",4);
for(int i=1;i<=n;i++)printf("%d ",i%4+1);
puts("");
}
}
return 0;
}
E. Coloring Game
首先发现如果不是二分图那么Alice之需要不停给出 \(1 2\) 即可
那么猜测在是二分图时选Bob,不是二分图时选Alice
思考Bob如何必胜
将二分图分为两堆,对于Alice给出的任意提问,优先考虑1仍在第一堆,2扔在第二堆,如果一堆满了,就把两种颜色的另一个扔在另一堆
比如当第一堆满了时,Alice给出 \(1 3\) ,那么就将3扔到第二堆
#include<bits/stdc++.h>
using namespace std;
int t,n,m;
struct edge{
int v,nx;
}e[20005];
int cnt,hd[10005];
void add(int u,int v){
e[++cnt]=edge{v,hd[u]};
hd[u]=cnt;
}
bool vis;
int col[10005];
queue<int> que[2];
void init(){
vis=1;
memset(hd,0,sizeof(hd));
memset(e,0,sizeof(e));
memset(col,0,sizeof(col));
}
void dfs(int u){
for(int i=hd[u];i;i=e[i].nx){
int v=e[i].v;
if(col[v]){
if(col[v]==col[u])vis=0;
continue;
}
col[v]=3-col[u];
dfs(v);
}
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
init();
for(int i=1;i<=m;i++){
int u,v;scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
for(int i=1;i<=n;i++)
if(!col[i]){
col[i]=1;
dfs(i);
}
if(!vis){
cout<<"Alice"<<endl;cout.flush();
for(int i=1;i<=n;i++){
cout<<"1 2"<<endl;
int u,v;scanf("%d%d",&u,&v);
cout.flush();
}
}else{
for(int i=1;i<=n;i++)que[col[i]-1].push(i);
cout<<"Bob"<<endl;cout.flush();
for(int i=1;i<=n;i++){
int c1,c2;scanf("%d%d",&c1,&c2);
if(c1>c2)swap(c1,c2);
if(c1==2 && c2==3){
if(!que[0].empty())cout<<que[0].front()<<" "<<c1<<endl,que[0].pop();
else if(!que[1].empty())cout<<que[1].front()<<" "<<c2<<endl,que[1].pop();
}else if(c1==1 && c2==3){
if(!que[1].empty())cout<<que[1].front()<<" "<<c2<<endl,que[1].pop();
else if(!que[0].empty())cout<<que[0].front()<<" "<<c1<<endl,que[0].pop();
}else if(c1==1 && c2==2){
if(!que[0].empty())cout<<que[0].front()<<" "<<c2<<endl,que[0].pop();
else if(!que[1].empty())cout<<que[1].front()<<" "<<c1<<endl,que[1].pop();
}
cout.flush();
}
}
}
return 0;
}
F. Triangle Formation
先思考如果只需求一个三角形时
正面比较难,所以该为研究什么情况下不存在三角形
将 \(a\) 从小到大排列
可以得出 \(a_{i+2} >= a{i+1} + a{i}\)
此时 \(a\) 将构成一个类似斐波那契数列的东西
可以得出在第45项 \(a_45 >= 1e9\)
所以如果询问区间大于45,就必定有一个三角形
那么如果需要求两个,那么对于一个长度超过48的区间
先将其中组成三角形的三个删去,剩余45个必然组成三角形
所以可得只要区间>=48就必定存在两个三角形
接下来考虑区间<=48的
只需要找第一个和最后一个连续3个组成三角形的边
判断他们是否重复,不重复则找到了两个三角形
然后在找连续6个边,考虑这6个边的所有分组情况是否存在组成两个三角形的
这样可以判定所有情况
大致证明:如果存在一种组成两个三角形的方法,不满足以上两条,那么一定可以将每个三角形的短边下标增大,或者长边下标减小,肯定更优,这样最后会贴到一起
#include<bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
#define ls (rt<<1)
#define rs (rt<<1|1)
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
int n,q,a[100005];
int b[155];
bool check(int l,int r){
if(r-l+1>=150)return 1;
int len=r-l+1;
for(int i=1;i<=len;i++)b[i]=a[l+i-1];
sort(b+1,b+1+len);
int loc1=0,loc2=0;
for(int i=1;i<=len-2;i++)
if(b[i]+b[i+1]>b[i+2]){
loc1=i;
break;
}
for(int i=len;i>=3;i--)
if(b[i-2]+b[i-1]>b[i]){
loc2=i-2;
break;
}
if(loc1 && loc2 && loc1+3<=loc2)return 1;
for(int i=1;i<=len-5;i++){
int u=b[i],v=b[i+1],w=b[i+2],x=b[i+3],y=b[i+4],z=b[i+5];
if(u+v>w && x+y>z)return 1;
if(u+v>x && w+y>z)return 1;
if(u+v>y && w+x>z)return 1;
if(u+v>z && w+x>y)return 1;
if(u+w>x && v+y>z)return 1;
if(u+w>y && v+x>z)return 1;
if(u+w>z && v+x>y)return 1;
if(u+x>y && v+w>z)return 1;
if(u+x>z && v+w>y)return 1;
if(u+y>z && v+w>x)return 1;
}
return 0;
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=q;i++){
int l,r;scanf("%d%d",&l,&r);
if(check(l,r))puts("YES");
else puts("NO");
}
return 0;
}
赛时为了稳直接做了150个的
浙公网安备 33010602011771号