题目链接
G-Xor Transformation
题目大意:
给定X和Y,需通过异或运算将X变成Y,其中Y<X。
每一次选择一个整数A与X进行异或运算,其中 0 ≤ A < X 0\leq A<X 0≤A<X。A的范围随着X的改变而改变。
最多只能对X做5次异或运算,求每一步A的值。
思路:考察异或运算的性质和应用
1)
X
⊕
X
=
0
X\oplus X=0
X⊕X=0
2)
X
⊕
0
=
X
X\oplus 0=X
X⊕0=X
由以上两条性质可以得出:
X
⊕
Y
⊕
X
=
Y
X\oplus Y\oplus X=Y
X⊕Y⊕X=Y
也就是说,直接让X异或上(
X
⊕
Y
X\oplus Y
X⊕Y),就可以成功把X变成Y了。
但是题目还有一个限制条件,就是X每次异或的数必须小于X,也就是说当(
X
⊕
Y
X\oplus Y
X⊕Y)时,我们不能直接让X与之异或。
注意到Y始终是小于X的,所以我们先让X异或上Y,此时X变成了(
X
⊕
Y
X\oplus Y
X⊕Y),这个值是大于之前的X,紧接着再异或上X,即可。
综上:
1、若
X
⊕
Y
<
X
X\oplus Y <X
X⊕Y<X:
一步到位,直接异或
X
⊕
Y
X\oplus Y
X⊕Y
2、若
X
⊕
Y
≥
X
X\oplus Y \geq X
X⊕Y≥X:
分为两步进行,先异或Y,再异或X
搞清楚了,就真的很简单,签到题了属于是。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ll x,y;
scanf("%lld%lld",&x,&y);
ll ans=x^y;
if(ans<x){
printf("1\n %lld\n",ans);
}
else{
printf("2\n");
printf("%lld %lld\n",y,x);
}
return 0;
}
C-Stone Game
题目大意:
有n堆石头,每堆至多三个石头,现需将所有石头合并成一堆。
将x个石头的石头堆与y个石头的石头堆合并成一堆,需要花费(x mod 3)(y mod 3)个硬币。求将所有石头合并成一堆最少花费多少个硬币。
思路:
(1) 由每次合并的花费(x mod 3)(y mod 3)可知,合并的两堆石头中只要出现一堆的石头数量是3的倍数就不用花钱。
所以那些石头数量是3的石头堆,我们是不用考虑的,首先将所有石头数量是3的石头堆全都合并成一堆,花费为0,合并之后石头数量仍为3的倍数。
(2) 假设石头个数为1的有X堆,石头个数为2的有Y堆。
将石头个数为1的一堆与石头个数为2的一堆合并,花费为2,合并之后石头数量为3的倍数(即可转化为 (1) 中的情况)
我们首先考虑将尽可能多的1和2合并,共需花费:2*min(X,Y)
(3)若
X
>
Y
X>Y
X>Y,
上述合并完成之后,只剩下
X
−
Y
X-Y
X−Y堆石头个数为1的石头堆。
对于个数为1的石头堆,每3堆合为1堆,花费为3,合并后石头数量为3的倍数。
如果
X
−
Y
X-Y
X−Y是3的倍数,则刚好能够每3堆合并完,总花费为
3
∗
(
X
−
Y
)
/
3
3*(X-Y)/3
3∗(X−Y)/3
如果每3堆合并完之后,还剩下一堆,因为此时其他的石头堆的石头数量全为3的倍数,将其他石头堆合并为一堆,不花钱且数量仍为3的倍数;此时只需再将剩下的那一堆和这一堆合并,也不用花钱,所以总花费也是
3
∗
(
X
−
Y
)
/
3
3*(X-Y)/3
3∗(X−Y)/3
如果每3堆合并完之后,还剩下两堆,先白这两堆合并,花费为1,然后和上述步骤一样操作,总花费为
3
∗
(
X
−
Y
)
/
3
+
1
3*(X-Y)/3+1
3∗(X−Y)/3+1
(4)若
X
>
Y
X>Y
X>Y
和(3)一样分析,只不过石头个数为2的堆石头堆每3堆合并,花费为6
其他同理。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
int ans=0;
if(x==y) ans=2*x;
else if(x>y){
ans=2*y;
x-=y;
if(x%3==2) ans+=3*(x/3)+1;
else ans+=3*(x/3);
}
else if(y>x){
ans=2*x;
y-=x;
if(y%3==2) ans+=6*(y/3)+4;
else ans+=6*(y/3);
}
printf("%d\n",ans);
return 0;
}
M-Cook Pancakes!
题目大意:
现有一个平底锅,n张煎饼,这口锅一次可以煎k张煎饼。每张煎饼都有两面,每面都需要一个小时才能煎好。问煎好n张煎饼需要花费的最少时间。
思路:
1、特判:
如果n<k,所有煎饼一起下锅,只需两个小时。
2、每个饼都需要煎两面,相当于有2n张只需要煎一面的饼。
每次可以煎k张,那总共就需要2n/k个小时。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
int n,k;
scanf("%d%d",&n,&k);
int ans=0;
if(k>=n) ans=2;
else ans=ceil(2.0*n/k);
printf("%d\n",ans);
return 0;
}
D-Fight against involution
题目大意:
有一门课程n个学生选,期末要写一篇论文。每个同学写的字数有一个下限和一个上限,课程的成绩是按学生字数的排名来给分的,排名越高分数越高,每个同学都想得到更高的成绩,而且他们都想写最少字数,那么在满足每个同学不能比原计划分数低的情况下求出所有同学总共要写的最少字数。
思路:
主要是要想清楚“不能比原计划分数低”,出于内卷考虑,每个人的原计划肯定都是得分越高越好,也就是说如果我能超过某人,那我就一定要超过,而不是“划水”。
先按照字数的上限从小到到排序,如果遇到上限相同的,就按字数下限从大到小排序。
如果我跟另外一个人上限是一样的,但我的下限比他的下限要大,那我又想写尽可能少的字,那就直接取下限,另外一个人跟我写一样的字数就行了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node {
ll l,r;
}arr[200010];
bool cmp(node a,node b) {
if(a.r==b.r) {
return a.l>b.l;
}
return a.r<b.r;
}
int main() {
int n;
scanf("%d",&n);
for(int i=0; i<n; i++) {
scanf("%lld%lld",&arr[i].l,&arr[i].r);
}
sort(arr,arr+n,cmp);
ll top = 0;
ll sum = 0;
for(int i=0; i<n; i++) {
arr[i].l = max(arr[i].l,top);
top = arr[i].l;
sum+=top;
}
printf("%lld\n",sum);
return 0;
}