我们的晚训难度更上一个层次了,其实仔细一想大家肯定都会做的。
从全球来看,2小时以内参赛并答题的选手,ABCDEFG题通过人数如图所示
你现在的实力在哪一档???
A题题解
太简单了。。。
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;
scanf("%d",&t);
while(t--){
int x,y;
scanf("%d%d",&x,&y);
printf("%d %d\n",min(x,y),max(x,y));
}
return 0;
}
B题题解
直接看看有没有一个位置相邻不同,交换即可
#include<bits/stdc++.h>
using namespace std;
char s[20];
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%s",s+1);
int n=strlen(s+1);
bool ok=false;
for(int i=2;i<=n;i++){
if(s[i]!=s[i-1]){
swap(s[i],s[i-1]);
ok=true;
break;
}
}
if(ok)printf("YES\n%s\n",s+1);
else printf("NO\n");
}
return 0;
}
C题题解
非常经典的判断区间相交问题,这个题的升级版本应该在atcoder出现过,给你N组这样子的线段,问有没有相交。其实就是判断区间相交,可以利用括号匹配的思路来做。先对所有区间端点排序,然后左端点看成L右端点看做R,括号匹配,如果此时的R匹配的是别人的L那么就有问题。
区间完全被包含或者独立,就不会有相交。
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;
scanf("%d",&t);
while(t--){
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
int La=min(a,b);
int Ra=max(a,b);
int Lb=min(c,d);
int Rb=max(c,d);
if(Lb<La&&La<Rb&&Rb<Ra){
printf("YES\n");
}
else if(La<Lb&&Lb<Ra&&Ra<Rb){
printf("YES\n");
}
else{
printf("NO\n");
}
}
return 0;
}
D题题解
其实你会发现连续的一段0 1 肯定是一起切的,先把数据简化,把连续的0 1压缩成单个1 0
然后你去找找规律,看看能发现啥? 10101010 0101010 要多少次
#include<bits/stdc++.h>
using namespace std;
char s[550];
char A[550];
int len=0;
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%s",s+1);
len=0;
int n=strlen(s+1);
for(int i=1;i<=n;i++){
A[++len]=s[i];
while(A[len]==s[i]&&i<=n)i++;
i--;
}
if(len==1||len==2&&A[1]=='0'&&A[2]=='1'){
printf("1\n");
}
else{
if(len==2)printf("2\n");
else printf("%d\n",len-1);
}
}
return 0;
}
E题题解
明白人一眼就能看出,Q次查询,每次问走了
D
[
i
]
D[i]
D[i]要多少时间,其实就是二分,因为
D
[
i
]
D[i]
D[i]可以处于某两个标记点中间,而每个标记点都有自己的到达时间。我们直接二分看看这个
D
[
i
]
D[i]
D[i]在哪,用匀速运动算出那一小段时间,再加上前面的即可。问题就在于每段区间的匀速速度,这个东西你要仔细看看数据,就会发现可能达到很大很大的程度,而double无法承载这种精度,而且题目也说了向下取整
我们分析每次查询的答案无外乎是某一个标记点的时间+匀速运动一小段的时间
匀速运动的时间=一小段路程/(区间距离 除以 区间时间) 我们把除法转换一下,把分母的除法乘上去,变成 一小段路程*区间时间 除以 区间距离 这个公式就是我们的匀速运动的时间,不整除也没事,反正不整除的部分也不考虑,因为答案向下取整,所以本题算时间得这样子算,注意long long
#include<bits/stdc++.h>
using namespace std;
struct pe{
long long int pos;
long long int time;
double v;
}A[100005];
int d;
bool check(int x,int y){
if(A[x].pos>y)return true;
else return false;
}
int Q[100005];
int main(){
int t;
scanf("%d",&t);
A[0].pos=0;
A[0].time=0;
while(t--){
int n,k,q;
scanf("%d%d%d",&n,&k,&q);
for(int i=1;i<=k;i++){
scanf("%d",&A[i].pos);
}
for(int i=1;i<=k;i++){
scanf("%d",&A[i].time);
//A[i].v=(A[i].pos-A[i-1].pos)*1.0/(A[i].time-A[i-1].time);
//之前我也是没注意到精度
}
A[k+1].pos=n+1;
for(int i=1;i<=q;i++){
scanf("%d",&Q[i]);
}
for(int i=1;i<=q;i++){
int L=1,R=k+1;
while(L<R){
int mid=(L+R)/2;
if(check(mid,Q[i])){
R=mid;
}
else{
L=mid+1;
}
}
printf("%lld ",A[R-1].time+ (long long int)((Q[i]-A[R-1].pos)*(A[R].time-A[R-1].time)/(A[R].pos-A[R-1].pos)));
}
printf("\n");
}
return 0;
}
F题题解
暴力枚举即可,根据四象限对称性质乘法即可
#include <bits/stdc++.h>
using namespace std;
int main() {
int t;
scanf("%d",&t);
while (t--) {
int r;
scanf("%d",&r);
int total = 0;
int x = -r;
int y = 0;
while (x != 0) {
int dist = x * x + y * y;
dist = sqrt(dist);
if (dist == r) {
total++;
y++;
} else if (dist > r) {
y--;
x++;
} else if (dist < r) {
y++;
}
}
cout << total * 4 << '\n';
}
return 0;
}
G题题解
还是异或运算,复习一遍,异或运算就是对两个数的二进制位操作,相同为0,不同为1
本题说两个数做异或<4才能交换位置,我们思考思考满足什么条件才能异或<4 ?
每个数的最低两位我们直接不考虑,我们考虑所有高位,但凡这两个数有一个高位不相同,那么异或的结果就是让该高位上的2进制的系数为1,因此异或结果绝对不可能<4
所以思路就很明确了: 对于除了前两位,其他2进制位完全相同的两个数字,才能进行交换位置
我们考虑标记,按二进制位进行映射标记,把除了前两位,其他位一样的数字标记到一起,他们内部可以任意交换,为了使得最终数组字典序最小,那肯定是小的摆前面去。
比如我举个例子,原数组里面1 3 5 7 9位置上面的 a b c d e数字满足可以任意交换,我们只需要把这5个数字按从小到大的顺序依次摆放在他们原本占据的位置上即可。
所以这个题我们需要标记,又因为不确定每种标记要放多少数字,所以vector就是很好的选择
标记map,以二进制串作为第一映射,vector作为第二映射
map<string,vector > 即我们把后缀一样的数字放在一起,注意我们还要标记这种后缀占据了哪些位置,因此需要两个标记。
#include<bits/stdc++.h>
using namespace std;
map<string,vector<int> >vel;
//后缀一样的放在一起,节点编号排序重新摆放
map<string,vector<int> >pos;
int A[200005];
int main(){
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&A[i]);
string s="";
int now=A[i];
A[i]=A[i]/2;
A[i]=A[i]/2;//移除最低的两个位
for(int j=1;j<=30;j++){
s+=('0'+A[i]%2);
A[i]=A[i]/2;
}
vel[s].push_back(now);//不必反转s
pos[s].push_back(i);
}
for(auto &Q: vel){
sort(Q.second.begin(),Q.second.end());
int len=Q.second.size();
for(int i=0;i<len;i++){
A[pos[Q.first][i]]=Q.second[i];
}
}
for(int i=1;i<=n;i++)
{
printf("%d ",A[i]);
}
printf("\n");
vel.clear();
pos.clear();
}
return 0;
}