A.XORwice
题意:
给定a,b,你可以随机选择一个数x,求(a⊕x)+(b⊕x)的最小值。
题解:
在二进制上每一位考虑,如果某一位都是1或0,那么x的这一位就是0,如果一个是1,一个是0,那么他x不管怎么选这一位都会留下。这个过程跟异或是一样的,所以就是a^b。
int main() {
for(scanf("%d",&_);_;_--){
a=rd();b=rd();
printf("%lld\n",a^b);
}
return 0;
}
B.Putting Bricks in the Wall
题意:
给定一个由01组成的地图,一条路径必须经过相同的点(全为0或全为1)。起点(1,1)和终点(n,n)不受上面的规则限制,问你在最多修改两个格子的情况下,如何使得起点到终点没有路径。
题解:
稍微思考一下就能明白,地图中很多点修改它没有意义,因为它总可能想一种办法让你的修改失效。比较有特征的就是起点旁边和终点旁边的点,这样的点只有4个。我们保证(2,1)(1,2)相同,(n,n-1)(n-1,n)相同且与(1,2)不相同即可
int _;
int n;
char s[maxn][maxn];
struct node{
int x,y;
};
int main() {
for(scanf("%d",&_);_;_--){
scanf("%d%*c",&n);
for (int i=1;i<=n;i++)scanf("%s",s[i]+1);
int ans=0;
vector<node>v;
if (s[2][1]==s[1][2]){
if (s[n-1][n]==s[2][1]){ans++;v.push_back({n-1,n});}
if (s[n][n-1]==s[2][1]){ans++;v.push_back({n,n-1});}
}
else{
if (s[n-1][n]==s[n][n-1]){
if (s[2][1]==s[n][n-1]){ans++;v.push_back({2,1});}
if (s[1][2]==s[n][n-1]){ans++;v.push_back({1,2});}
}
else{
if (s[1][2]=='1'){ans++;v.push_back({1,2});}
if (s[2][1]=='1'){ans++;v.push_back({2,1});}
if (s[n-1][n]=='0'){ans++;v.push_back({n-1,n});}
if (s[n][n-1]=='0'){ans++;v.push_back({n,n-1});}
}
}
printf("%d\n",ans);
for (auto u:v)printf("%d %d\n",u.x,u.y);
}
return 0;
}
C.Palindromifier
题意:给定一个字符串,有两种操作,第一种是你选择2-i的子串,将其复制一遍然后翻转接到原串前面,第二种是你选择i-(n-1)的子串,将其复制一遍然后翻转接到原串后面。让你给出在30次操作以内将这个字符串变成回文串的操作方法。(2<=i<=n-1)
题解:
构造题就在纸上画画瞎搞(不是
手玩一会发现,如果第n-2个元素等于第n个元素,那我把2-n-1翻过去,然后把当前的第二个元素放到后面就成功了。那就是构造出第n-2个元素等于第n个了,这个简单 直接把当前的第n-1个翻到后面就完成了。
int main() {
cin>>s;
n=s.size();
puts("3");
printf("R %d\n",n-1);
printf("L %d\n",n);
printf("L %d\n",2);
return 0;
}
D.Hexagons
题意:
给你一个蜂窝图,你每次可以往6个方向走,每次走的花费是给定的,问你从(0,0)到(n,m)的最小花费
题解:
一个方向的走法可以由另外两个操作完成可能是更优的,所以我们先处理出这个走法的最小花费。
然后我们根据6个方向将整个平面划分成6个象限。每个象限里仅用两种操作,这样你就发现走法是唯一的,直接统计一下就行。(因为我初始已经把一小步用别的一小步尝试优化了一下,所以已经没必要绕一下走了)
ps.盯着图一个个推怎么写真的费眼
int _;
ll x,y;
ll c[10],a[10];
int main() {
for(scanf("%d",&_);_;_--){
x=rd();y=rd();
for (int i=1;i<=6;i++)a[i]=rd();
c[1]=min(a[1],a[2]+a[6]);
c[2]=min(a[2],a[1]+a[3]);
c[3]=min(a[3],a[2]+a[4]);
c[4]=min(a[4],a[3]+a[5]);
c[5]=min(a[5],a[6]+a[4]);
c[6]=min(a[6],a[1]+a[5]);
if (x>=0&&y>=0&&y>=x){
printf("%lld\n",c[1]*x+c[2]*(y-x));
}
else if (x<=0&&y>=0){
printf("%lld\n",c[3]*(-x)+c[2]*y);
}
else if (x>=0&&y<=x&&y>=0){
printf("%lld\n",c[1]*y+(x-y)*c[6]);
}
else if (x>=0&&y<=0){
printf("%lld\n",c[6]*x+c[5]*(-y));
}
else if (x<=0&&y<=x){
printf("%lld\n",(-x)*c[4]+(x-y)*c[5]);
}
else{
printf("%lld\n",(-y)*c[4]+(y-x)*c[3]);
}
}
return 0;
}
E.Swedish Heroes
题意:给定一个数列,你每次选择a[i]a[i]a[i]和a[i+1]a[i+1]a[i+1]删掉然后放回−(a[i]+a[i+1])-(a[i]+a[i+1])−(a[i]+a[i+1])问n−1n-1n−1次操作后,留下的数最大是多少
题解:
对于这道题我们可以等价的看作在每一个数前面加上符号最后求和。
这道题的做法有一个归纳性的结论:设数列的长度为nnn,负号的数量为mmm,那么(n+m)(n+m)(n+m)%3=13=13=1.并且满足你的符号放置不能以+ - + - + -这样交替放置。
证明过程:这里采用数学归纳法的思想来证明。
n=1n=1n=1时,m=0m=0m=0,(n+m)(n+m)(n+m)%3=13=13=1。
n=2n=2n=2时,m=2m=2m=2,(n+m)(n+m)(n+m)%3=13=13=1.
那么一步操作时,假设左边的数共有n1n1n1个,负号有m1m1m1个,右边的数有n2n2n2个,负号有m2m2m2个.此时满足(n1+m1)(n1+m1)(n1+m1)%3=1,(n2+m2)3=1,(n2+m2)3=1,(n2+m2)%3=13=13=1
操作后,n=n1+n2,m=(n1−m1)+(n2−m2)−>(n+m)n=n1+n2,m=(n1-m1)+(n2-m2)->(n+m)n=n1+n2,m=(n1−m1)+(n2−m2)−>(n+m)%3=13=13=1
所以我们只需要最大化(n+m)(n+m)(n+m)%3=13=13=1的情况下,所有数和最大。
至于为什么不能+ - + -,我们在第一步操作后选中a[i]和a[i+1]他们在后续的操作中符号一定是相同的,不可能符号相反。
至此证毕。
具体的实现考虑dp的处理。
dp[i][j][0]dp[i][j][0]dp[i][j][0]代表处理到i位,(i+m)(i+m)(i+m)%3=j3=j3=j,尚未出现连续相同符号的1−i1-i1−i的最大和
dp[i][j][1]dp[i][j][1]dp[i][j][1]代表处理到i位,(i+m)(i+m)(i+m)%3=j3=j3=j,已经出现连续相同符号的1−i1-i1−i的最大和
每次dp[i]dp[i]dp[i]可以从dp[i−2]dp[i-2]dp[i−2]转移过来,通过控制第iii个元素和第i−1i-1i−1个前的符号实现转移。
同时,如果dp[i−1][j][1]dp[i-1][j][1]dp[i−1][j][1]有值,也可以直接转移到dp[i]dp[i]dp[i].
int n,a[maxn];
ll dp[maxn][3][2];
int change[4][2]={1,1,-1,-1,1,-1,-1,1};
int num[4]={2,4,3,3};
int main() {
n=rd();
for (int i=1;i<=n;i++)a[i]=rd();
if (n==1){printf("%d\n",a[1]);return 0;}
for (int i=0;i<=n;i++)for (int j=0;j<3;j++)for (int k=0;k<2;k++)dp[i][j][k]=-inf;
dp[0][0][0]=0;
dp[1][1][0]=a[1];
dp[1][2][0]=-a[1];
for (int i=2;i<=n;i++){
for (int j=0;j<3;j++){
for (int d=0;d<4;d++){
int f=a[i-1]*change[d][0],g=a[i]*change[d][1];
for (int k=0;k<2;k++)
if (dp[i-2][j][k]!=-inf){
if (d<2)
dp[i][(j+num[d])%3][1]=max(dp[i][(j+num[d])%3][1],dp[i-2][j][k]+f+g);
else
dp[i][(j+num[d])%3][k]=max(dp[i][(j+num[d])%3][k],dp[i-2][j][k]+f+g);
}
}
if (dp[i-1][j][1]!=-inf){
dp[i][(j+1)%3][1]=max(dp[i][(j+1)%3][1],dp[i-1][j][1]+a[i]);
dp[i][(j+2)%3][1]=max(dp[i][(j+2)%3][1],dp[i-1][j][1]-a[i]);
}
}
}
cout<<dp[n][1][1]<<endl;
return 0;
}
本文精选了五道算法竞赛题目并提供了详细的解答思路,包括异或运算性质的应用、地图路径规划、字符串操作构造、蜂窝图最短路径及数列操作优化等问题。
1142

被折叠的 条评论
为什么被折叠?



