【GDKOI】2021普及Day2
第一题 初中生数学题
提交文件: math.cpp
输入文件: math.in
输出文件: math.out
时间空间限制: 1s, 512MB
你已经上初中了,相信你一定会做这道题。
给定 10 个正整数,记为 a1, a2, a3, · · · , a10。 令 x = 1a1 × 2a2 × 3a3 × · · · × 10a10。 求 x 在 10 进制下从低位到高位的第一个非 0 位上的数字是多少。
输入格式
一行,10 个非负整数,分别表示 a1, a2, a3, · · · , a10。
输出格式
一行,一个非负整数,表示第一个非 0 位上的数字是多少。
样例数据
math.in
1 2 1 0 2 1 0 0 0 3
math.out
8
样例解释
1 × 22 × 3 × 52 × 6 × 103 = 1800000
数据范围
对于 30% 的数据,保证
∑i=1~10, ai ≤ 9。
对于另外 20% 的数据,保证除 a2 和 a5 外,其他数字全部为 0。
对于 100% 的数据,保证 ai ≤ 105 。
代码
#include<iostream>
#include<cstdio>
using namespace std;
long long a[110];
int main()
{
long long i;
long long ans=1;
freopen("math.in","r",stdin);
freopen("math.out","w",stdout);
for(i=1;i<10;i++)
scanf("%lld",&a[i]);
a[2]+=a[6]+(a[4]<<1)+(a[8]<<1)+a[8];
a[3]+=a[6]+(a[9]<<1);
a[4]=a[6]=a[8]=0;
if(a[2]>a[5]) for(i=a[2]-a[5];i;ans=(ans<<1)%10,i--);
else for(i=a[5]-a[2];i;ans=(ans*5)%10,i--);
for(i=0;i<a[3];ans=ans*3%10,i++);
for(i=0;i<a[7];ans=ans*7%10,i++);
printf("%lld",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
第二题 二叉树
提交文件: tree.cpp
输入文件: tree.in
输出文件: tree.out
时间空间限制: 3s, 512MB
给定一颗搜索二叉树的 BFS 序,请判断该棵二叉树是否为正则二叉树。
下面是一些可能有用的定义:
正则二叉树 一颗有根二叉树,满足每个节点要么是叶子节点,要么一定有两个儿子。
搜索二叉树 一颗有根二叉树,满足任意一个节点 k,k 左子树的任一节点的权值小于等于节点 k 的权值,k
右子树的任一节点的权值大于等于节点 k 的权值。
二叉树的 BFS 序 以离根节点的距离为顺序进行遍历。其中,将子节点加入队列时,左侧儿子节点优先级高
于右侧儿子节点。
输入格式
输入包含多组测试数据。
第一行一个整数 T,表示该测试点所包含的数据组数。
对于每组测试数据,
第一行一个整数 n,表示搜索二叉树的节点个数。
第二行给出一个大小为 n 的排列,表示搜索二叉树的 BFS 序。
本题输入输出量较大,请使用较快的输入输出方式。
输出格式
共 T 行,每行输出 YES 或 NO,表示该棵搜索二叉树是否正则二叉树.
样例数据
tree.in
25
2 1 4 3 5
5
3 2 4 1 5
tree.out
YES
NO
数据范围
对于 30% 的数据, 保证 T ≤ 100, n ≤ 500。
对于 60% 的数据, 保证 T ≤ 100, n ≤ 5 × 103。
对于 100% 的数据, 保证 T ≤ 100, n ≤ 105。
代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
struct t
{
int l,r,s;
};
t tree[4000010];
int c,mx,tot,x,mxs;
queue<int> que,que_;
void inserttree(int w)
{
if(tree[tot].s<=tree[w].s)
if(tree[w].l==0)
tree[w].l=tot;
else
c++,inserttree(tree[w].l);
else
if(tree[w].r==0)
tree[w].r=tot;
else
c++,inserttree(tree[w].r);
return;
}
bool BFS()
{
int tem;
que=que_;
for(que.push(1);!que.empty();que.pop())
{
tem=que.front();
if((tree[tem].l>0)^(tree[tem].r>0)) return 0;
else if((tree[tem].l>0)&&(tree[tem].r>0)) que.push(tree[tem].l),que.push(tree[tem].r);
}
return 1;
}
int main()
{
int T,i,n;
t tem;
tem.l=tem.r=tem.s=0;
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
for(scanf("%d",&T);T;T--)
{
scanf("%d",&n);
for(i=1;i<=n;i++)
tree[i]=tem;
if(n==0)
{
printf("NO\n");
for(i=0;i<n;scanf("%*d"),i++);
}
else
{
tot=1;
scanf("%d",&tree[1].s);
mxs=tree[1].s;
for(mx=1,i=1;i<n;i++)
{
scanf("%d",&tree[++tot].s);
c=2;
inserttree(1);
if(c>mx)
{
mx=c;
mxs=tree[tot].s;
}
else
{
if(c==mx)
{
if(tree[tot].s<mxs)
{
printf("NO\n");
for(i++;i<n;scanf("%*d"),i++);
}
else
mxs=tree[tot].s;
}
else
{
printf("NO\n");
for(i++;i<n;scanf("%*d"),i++);
}
}
}
if(i==n)
if(BFS())
printf("YES\n");
else
printf("NO\n");
else;
}
}
fclose(stdin);
fclose(stdout);
return 0;
}
第三题 我的世界
提交文件: minecraft.cpp
输入文件: minecraft.in
输出文件: minecraft.out
时间空间限制: 1s, 512MB
众所周知,在我的世界这个游戏中具有主世界以及下界两个世界,主世界与下界存在一定的关系。具体
来说,主世界的水平坐标与下界的水平坐标为 8 : 1。也就是说,在下界移动 1 个单位的距离,相当于主世界
移动 8 个单位的距离。
在得知这个规律后,小 A 希望通过这个方法迅速到达自己想去的地方。在小 A 的世界中,小 A 探索过
的地方可以用一棵 n 个节点的树来表示(即:主世界和下界都是这样的一棵树)。我们用 (x, y, w) 表示树上
一条双向边,表示在下界中走过这条边需要 w 的时间,在主世界中走过这条边需要 8w 的时间。虽然在下界
可以快速移动,但我们需要通过下界传送门来到达下界或者回到主世界,在主世界的节点 i 使用一次下界传
送门可以到达下界的节点 i,在下界的节点 i 使用一次下界传送门可以回到主世界的节点 i,二者花费的时间
都是 ai。
现在小 A 有 q 个行动计划,每个计划希望从主世界的 x 节点到达主世界的 y 节点。因为地图上有各种
各样的怪物,所以小 A 希望知道在通过尽量少的节点的前提下,每个计划最少需要多少时间?
输入格式
第一行一个整数 n,表示树的节点数。
第二行 n 个整数,第 i 个整数 ai 表示节点 i 使用一次下界传送门需要花费的时间。
接下来 n 1 行,每行三个整数 x, y, w,表示树上的一条双向边。
接下来一行,一个整数 q,表示行动计划的数量。
接下来 q 行,每行两个整数 x, y,表示行动计划的起始节点和目标节点。
输出格式
输出 q 行,每行一个整数,表示行动计划最少需要的时间。
样例数据
minecraft.in
5
17 3 19 7 9
1 3 3
3 4 1
1 2 1
4 5 1
5
1 4
1 2
3 5
2 4
2 5
minecraft.out
28
8
16
15
18
数据范围
对于 40% 的数据,n, q ≤ 5000。
对于所有数据,n, q ≤ 2 × 105, 1 ≤ x, y ≤ n, 0 < ai, w ≤ 109。
代码
用LCA。
错误代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
int a[1010][1010],b[1010][1010];
bool d[1010];
int main()
{
int i,j,n;
freopen("matrix.in","r",stdin);
freopen("matrix.out","w",stdout);
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(d,0,sizeof(d));
scanf("%d",&n);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
scanf("%d",&a[i][j]);
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(a[i][j]==2)
b[i][j]=1,d[j]=1,j=n;
if(a[i][j]==1)
if(!d[j])
b[i][j]=1,d[j]=1,j=n;
}
}
for(i=1;i<=n;putchar('\n'),i++)
for(j=1;j<=n;j++)
printf("%d ",b[i][j]);
for(i=1;i<=n;putchar('\n'),i++)
for(j=1;j<=n;j++)
printf("%d ",a[i][j]-b[i][j]);
fclose(stdin);
fclose(stdout);
return 0;
}
第四题 矩阵
提交文件: matrix.cpp
输入文件: matrix.in
输出文件: matrix.out
时间空间限制: 1s, 512MB
有一个 n × n 的矩阵 A,令 ri 表示 A 的第 i 行的元素的和,cj 表示 A 的第 j 列的元素的和。
A 是一个特殊的矩阵,满足所有 ri 以及 cj 都是偶数。
现在要将 A 分成两个矩阵,即求 n × n 的矩阵 B 和 C 满足
A = B + C B 和 C 的元素都是非负整数,且对于任意 1 ≤ i ≤ n,B 的第 i 行的元素和等于 C 的第 i 行的元素和;
对于任意 1 ≤ j ≤ n,B 的第 j 列的元素和等于 C 的第 j 列的元素和。
输入格式
第一行一个整数 n。
接下来 n 行,每行 n 个整数,表示矩阵 A。
输出格式
输出 2n 行,每行 n 个数字,前 n 行表示矩阵 B,后 n 行表示矩阵 C。
注:样例输出为了更易读,在矩阵之间增加了一个空行,选手在答题时无需输出空行。
样例数据
matrix.in
3
1 8 7
5 6 3
2 4 0
matrix.out
0 3 5
2 5 0
2 1 0
1 5 2
3 1 3
0 3 0
数据范围
对于所有数据,n ≤ 1000, 0 ≤ Aij ≤ 109。
对于 30% 的数据,n ≤ 100;
对于另外 20% 的数据,0 ≤ Aij ≤ 1;
对于另外 20% 的数据,A 每行每列的和都是 2。
代码
错误:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
int a[1010][1010],b[1010][1010];
bool d[1010];
int main()
{
int i,j,n;
freopen("matrix.in","r",stdin);
freopen("matrix.out","w",stdout);
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(d,0,sizeof(d));
scanf("%d",&n);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
scanf("%d",&a[i][j]);
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(a[i][j]==2)
b[i][j]=1,d[j]=1,j=n;
if(a[i][j]==1)
if(!d[j])
b[i][j]=1,d[j]=1,j=n;
}
}
for(i=1;i<=n;putchar('\n'),i++)
for(j=1;j<=n;j++)
printf("%d ",b[i][j]);
for(i=1;i<=n;putchar('\n'),i++)
for(j=1;j<=n;j++)
printf("%d ",a[i][j]-b[i][j]);
fclose(stdin);
fclose(stdout);
return 0;
}