A - XORwice
题目大意
给你 (a) 和 (b),求 ((a oplus x) + (b oplus x)) 的最小值。
解题思路
考虑怎么构造 (x) 才能使要求的值最小。
对于每一位,如果 (a,b) 都是 (0) ,那么当 (x) 的这一位为 (0) 时,异或后的这一位一定是零,肯定最优。
如果 (a,b) 一个是 (1),一个是 (0) ,那么当 (x) 的这一位不论是 (0) 还是 (1) ,异或后一定是一 (0) 一 (1) ,不妨就认为 (x) 的这一位是 (0)。
如果 (a,b) 都是 (1) ,那么当 (x) 的这一位为 (1) 时,异或后的这一位一定是零,肯定最优。
简单观察就能发现,上面的构造其实就是 (a land b)。
所以答案就是 ((a oplus (a land b)) + (b oplus (a land b)))
Code
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<bitset>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define int long long
using namespace std;
int read()
{
int ans=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
return ans*f;
}
int t,a,b;
signed main()
{
t=read();
while(t--)
{
a=read();b=read();
printf("%lld
",(a^(a&b))+(b^(a&b)));
}
return 0;
}
B - Putting Bricks in the Wall
题目大意
给定一个 (01) 矩阵,一个人会从 ((1,1)) 走到 ((n,n)),他途中会只走 (0) 或直走 (1)。
现在可以将做多两个格子 (01) 反转,使得这个人无法找到一条可行的路径
解题思路
显然如果 ((2,1),(1,2)) 两个格子的数字与 ((n,n-1),(n-1,n)) 的数字不同,就一定没有可行路径,因为路径必定经过这四个格子的其中两个。
所以分类讨论一下就好了,显然可以在两次反转内做到这件事。
Code
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<bitset>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define int long long
using namespace std;
int read()
{
int ans=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
return ans*f;
}
const int N=205;
int t,n;
char mmap[N][N];
signed main()
{
t=read();
while(t--)
{
n=read();
for(int i=1;i<=n;++i)
scanf("%s",mmap[i]+1);
if(mmap[1][2]=='0'&&mmap[2][1]=='0')
{
if(mmap[n][n-1]=='1'&&mmap[n-1][n]=='1')
printf("0
");
else if(mmap[n][n-1]=='1')
printf("1
%lld %lld
",n-1,n);
else if(mmap[n-1][n]=='1')
printf("1
%lld %lld
",n,n-1);
else printf("2
%lld %lld
%lld %lld
",n,n-1,n-1,n);
}
else if(mmap[1][2]=='0'&&mmap[2][1]=='1')
{
if(mmap[n][n-1]=='1'&&mmap[n-1][n]=='1')
printf("1
%lld %lld
",2,1);
else if(mmap[n][n-1]=='1')
printf("2
%lld %lld
%lld %lld
",2,1,n-1,n);
else if(mmap[n-1][n]=='1')
printf("2
%lld %lld
%lld %lld
",2,1,n,n-1);
else printf("1
%lld %lld
",1,2);
}
else if(mmap[1][2]=='1'&&mmap[2][1]=='0')
{
if(mmap[n][n-1]=='1'&&mmap[n-1][n]=='1')
printf("1
%lld %lld
",1,2);
else if(mmap[n][n-1]=='1')
printf("2
%lld %lld
%lld %lld
",1,2,n-1,n);
else if(mmap[n-1][n]=='1')
printf("2
%lld %lld
%lld %lld
",1,2,n,n-1);
else printf("1
%lld %lld
",2,1);
}
else
{
if(mmap[n][n-1]=='0'&&mmap[n-1][n]=='0')
printf("0
");
else if(mmap[n][n-1]=='0')
printf("1
%lld %lld
",n-1,n);
else if(mmap[n-1][n]=='0')
printf("1
%lld %lld
",n,n-1);
else printf("2
%lld %lld
%lld %lld
",n,n-1,n-1,n);
}
}
return 0;
}
C - Palindromifier
题目大意
给一个 (n) 个字符的字符串,每次操作可以选择将 (2 sim i) 的字符反转并添加到字符串的前部或将 (i sim n-1) 的字符串反转并添加到字符串的末尾。
在 (30) 次操作内使得这个字符串回文。
解题思路
个人觉得这个 (30) 挺误导人的。
因为可以 (3) 次操作就做到这件事。
-
把 (2 sim 2) 反转并添加到字符串前部,这样假设原来字符串是 (XOXXX...) ,反转后就能得到 (OXOXXX...)
-
把 (2 sim n-1) 反转并添加到字符串尾部,这样假设原来字符串是 (OXOXXX...),那么反转后的字符串就是 (OXOXXX......XXXOX),此时 (2sim n) 已经回文。
-
把 (n-1 sim n-1) 反转并添加到字符串尾部,这样假设原来字符串是 (OXOXX......XXOX),那么反转后的字符串就是 (OXOXX......XXOXO),显然回文。
(Ps:上述中的 (O) 为一固定字符,(X) 为任意字符,且 (n) 是每次操作后的字符串长度而非读入的字符串长度)
Code
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<bitset>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define int long long
using namespace std;
int read()
{
int ans=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
return ans*f;
}
const int N=1e5+5;
int n;
char s[N];
signed main()
{
scanf("%s",s+1);
n=strlen(s+1);
printf("3
");
printf("L 2
");n++;
printf("R 2
");n+=n-2;
printf("R %lld
",n-1);
return 0;
}
D - Hexagons
题目大意
有一个二元组 ((a,b)) ,每次可以把这个二元组进行 ((a+1,b+1),(a,b+1),(a-1,b),(a-1,b-1),(a,b-1),(a+1,b)) 的加减操作。
已知每种操作的代价(代价为正数),初始时的二元组为 ((0,0)),求把二元组变成 ((x,y)) 需要的最小代价。
解题思路
显然分类讨论,通常可以分为三种情况:
-
((x,y)) 直接通过 ((a,b+1),(a-1,b),(a,b-1),(a+1,b)) 加减到位。
-
先通过 ((a+1,b+1),(a-1,b-1)) 把同时加减到 ((x,x)),再通过第一种情况加减到 ((x,y))。
-
先通过 ((a+1,b+1),(a-1,b-1)) 把同时加减到 ((y,y)),再通过第一种情况加减到 ((x,y))。
这题初值要设到 (2 imes 10^{18}),然后我习惯性的设成了 (10^{18}) 就没了qwq
Code
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<bitset>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define int long long
using namespace std;
int read()
{
int ans=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
return ans*f;
}
int t,x,y,C1,C2,C3,C4,C5,C6;
signed main()
{
t=read();
while(t--)
{
x=read();y=read();
C1=read();C2=read();C3=read();
C4=read();C5=read();C6=read();
int ans=1e19;
if(x==0&&y==0) ans=0;
else if(x<=0&&y<=0)
{
x=-x,y=-y;
ans=min(ans,x*C3+y*C5);
if(x>=y) ans=min(ans,y*C4+(x-y)*C3);
else ans=min(ans,x*C4+(y-x)*C5);
if(x>=y) ans=min(ans,x*C4+(x-y)*C2);
else ans=min(ans,y*C4+(y-x)*C6);
}
else if(x<=0&&y>=0)
{
x=-x;
ans=min(ans,x*C3+y*C2);
ans=min(ans,x*C4+(x+y)*C2);
ans=min(ans,y*C1+(x+y)*C3);
}
else if(x>=0&&y<=0)
{
y=-y;
ans=min(ans,x*C6+y*C5);
ans=min(ans,x*C1+(x+y)*C5);
ans=min(ans,y*C4+(x+y)*C6);
}
else
{
ans=min(ans,x*C6+y*C2);
if(x>=y) ans=min(ans,y*C1+(x-y)*C6);
else ans=min(ans,x*C1+(y-x)*C2);
if(x>=y) ans=min(ans,x*C1+(x-y)*C5);
else ans=min(ans,y*C1+(y-x)*C3);
}
printf("%lld
",ans);
}
return 0;
}