前言
终于给小号上紫啦!
这场前期很顺利,后期也稳住了,但是E读错题了,不然还是可以试试的。
开场推A的公式,往下一翻,数据范围100,n^2直接过掉,3min1A
,
然后看B,排序就完事了,然后被网速卡了5min提交,12min1A
开C,这个n+1有意思,想了一会发现倒着做很简单,22min1A
之后发现D一个过的都没有,看了一下题意发现有点难,推一推吧
画了好多个01串,发现什么都获取不到啊!之后有人过了,继续推。
发现相等的情况好写,之后继续推,发现都可以,只是实现有些费劲,由于数据范围读错wa1,但是wa1不扣分,79min1A
还有40min看E,其实应该好好看看的,但是自己已经写完D疲惫了,于是就划水到结束
biubiubiu_
r
a
t
i
n
g
+
=
77
rating+=77
rating+=77 1890->1967
A. Ehab and another construction problem
题意
给你一个数字x,1<=x<=100,找出一对数字a,b满足
1
<
=
a
,
b
<
=
x
1<=a,b<=x
1<=a,b<=x
a
是
b
的
倍
数
a是b的倍数
a是b的倍数
a
∗
b
>
x
a*b>x
a∗b>x
a
/
b
<
x
a/b<x
a/b<x
做法
由于x的范围比较小,直接for循环枚举a,b, O ( n 2 ) O(n^2) O(n2)
代码
#include<stdio.h>
int main()
{
int x;
scanf("%d",&x);
for(int i=1;i<=x;i++)
{
for(int j=1;j<=x;j++)
{
if(i%j==0)
{
if(i*j>x&&i<j*x)
{
printf("%d %d\n",i,j);
return 0;
}
}
}
}
printf("-1\n");
return 0;
}
B. Ehab and subtraction
题意
给你一个大小为n的数组,进行k次操作
每次找到最小的非0数,输出这个数之后所有非0数减去这个数,
1
<
=
n
,
k
<
=
1
0
5
1<=n,k<=10^5
1<=n,k<=105
做法
由于每次都是所有数一起减去一个数,所以大小关系和最初是不变的,
于是sort一下,从前往后减去大于0的数即可,用一个变量记录当前一共减了多少
之后不足的操作全部输出0
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
ll a[maxn];
int main()
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++ ) scanf("%lld",&a[i]);
sort(a+1,a+1+n);
ll tmp=0;
for(int i=1;i<=n;i++)
{
if(a[i]-tmp>0)
{
k--;
printf("%lld\n",a[i]-tmp);
tmp+=(a[i]-tmp);
}
if(k==0) break;
}
while(k--) printf("0\n");
return 0;
}
C. Ehab and a 2-operation task
题意
给你一个数组,有两种操作,
第一种操作是选择一段前缀全部加上x
第二种操作是选择一段前缀全部%x
最终用不超过n+1个操作构造一个递增数组
做法
我们考虑有Mod操作,所以其实数字可以加到特别大,最后一次Mod降下来就可以
而我们从后往前构造,就保证之后的操作不会影响之前的操作
然后我们只要让第i个数字%Mod=i就可以了。
由于数字最大值为1e5,所以这里Mod我选择的是1e5+7
之后每个数字先加上之前操作的贡献再%Mod
这是数字是小于Mod的,我们只要加上一些让它变成Mod+i就可以了。
代码
#include<stdio.h>
typedef long long ll;
const int maxn = 1e5+5;
const int Mod=100007;
int a[maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
ll tt=0;
printf("%d\n",n+1);
for(int i=n;i>=1;i--)
{
ll fin=i+Mod;
ll now=(tt+a[i])%Mod;
printf("1 %d %d\n",i,(fin-now+Mod)%Mod);
tt=(tt+(fin-now+Mod)%Mod)%Mod;
}
return 0;
}
D. Ehab and another another xor problem
题意
这是一道交互题,一开始有两个数a,b,
0
<
=
a
,
b
<
=
2
30
0<=a,b<=2^{30}
0<=a,b<=230
你一共最多提问62次,每一次用两个数c,d提问
每个提问有三种返回结果
如
果
a
⊕
c
>
b
⊕
d
如果 a \oplus c> b \oplus d
如果a⊕c>b⊕d 返回1
如
果
a
⊕
c
=
b
⊕
d
如果 a \oplus c= b \oplus d
如果a⊕c=b⊕d 返回0
如
果
a
⊕
c
<
b
⊕
d
如果 a \oplus c<b \oplus d
如果a⊕c<b⊕d 返回-1
让你在不超过62次询问后,输出a,b
做法
这个题这个62次询问,可能会给我们一些提示,
我们想一下怎么确定两个数的第一个不相同位
如果两个数大小相同,那么我们只需要从高位到低位不断
a
⊕
2
i
a\oplus 2^i
a⊕2i 如果当前为异或之后a>b 则这一位为0,否则这一位为1
如果两个数不相同,一定是一个大一个小,而且一定是第一个不相同位决定大小
我们先让两个数同时
⊕
0
\oplus 0
⊕0,这样就能判断两个数的大小关系,
如果当前剩余位a>b
一定是这样的一个01串
a:xxxxxx1xxxxxx
b:xxxxxx0xxxxxx
在这个1,0之前a,b是相同的,之后的不用管,
那么我们让
a
⊕
2
i
b
⊕
2
i
a\oplus 2^i \ \ \ b\oplus2^i
a⊕2i b⊕2i
本来a>b,如果到了某一位异或之后返回a<b,那么可以确定a这一位为1,b这一位为0
如果返回a>b,则说明a,b在这一位相同,用之前判相同得方法判断即可,
如果当前剩余位a<b
将上述过程反过来做即可。
而这里要注意一个问题,每次找到一个不同位,用两个变量记录a,b之前的所有1的贡献
每次找到一个不同的位之后,就可以去掉之前的贡献重新判断剩余位两个数的大小关系,
问题就转换为相同性质的子问题,不断往后做就可以了。
代码
#include<stdio.h>
#include<iostream>
using namespace std;
typedef long long ll;
int main()
{
ll flagc=0,flagd=0;
ll ansc=0,ansd=0;
int x,k=29;
int ff=0;//ff==0 相等 ff==1 大于 ff==-1 小于
printf("? 0 0\n");
fflush(stdout);
scanf("%d",&ff);
while(k>=0)
{
ll tt=(1LL<<k);
if(ff==0)
{
printf("? %lld %lld\n",flagc^tt,flagd);
fflush(stdout);
scanf("%d",&x);
if(x==-1)
{
ansc=ansc^tt;
ansd=ansd^tt;
}
}
else if(ff==-1)
{
printf("? %lld %lld\n",flagc^tt,flagd^tt);
fflush(stdout);
scanf("%d",&x);
if(x==1)
{
ansd=ansd^tt;
flagd=flagd^tt;
printf("? %lld %lld\n",flagc,flagd);
fflush(stdout);
scanf("%d",&ff);
}
else
{
printf("? %lld %lld\n",flagc^tt,flagd);
fflush(stdout);
scanf("%d",&x);
if(x==-1)
{
ansc=ansc^tt;
ansd=ansd^tt;
}
}
}
else if(ff==1)
{
printf("? %lld %lld\n",flagc^tt,flagd^tt);
fflush(stdout);
scanf("%d",&x);
if(x==-1)
{
ansc=ansc^tt;
flagc=flagc^tt;
printf("? %lld %lld\n",flagc,flagd);
fflush(stdout);
scanf("%d",&ff);
}
else
{
printf("? %lld %lld\n",flagc^tt,flagd);
fflush(stdout);
scanf("%d",&x);
if(x==-1)
{
ansc=ansc^tt;
ansd=ansd^tt;
}
}
}
k--;
}
printf("! %lld %lld",ansc,ansd);
fflush(stdout);
return 0;
}