比赛开始,按照惯例,我把5题都看了一遍,认为按原有顺序做题应该是一种正确的做题顺序,就开始做题了
T1:Classroom Watch (num.cpp)
【问题描述】
给出一个正整数 n n n,现在问存在多少个 x x x,使得 x x x在十进制下的每一位之和加上 x x x 等于 n n n。
【输入】
共 1 行,一个正整数 n n n 。
【输出】
第一行输出一个整数
m
m
m,表示有
m
m
m个符合条件的 (若没有符合条件的 ,请只输出一个
0
0
0)。
下面
m
m
m行,每行一个
x
,
x
x ,x
x,x按从小到大输出。
心路历程:
对于这道题,我认为我充分做到了
O
l
d
Old
Old
L
i
u
Liu
Liu的话——将简单的题目复杂化。
我拿到这道题,经过
10
m
i
n
10min
10min的思考,我列出了一个方程,成功走向弯路。
还好,经过好长一段时间,我对我的思路产生了疑惑,又重新将题目好好读了一遍,静下心来用心思考后找到了正确的道路,将思路归为正轨。
题目分析:
我们仔细观察题目条件,在十进制下,那么对于任意正整数n,那么每个数位范围一定是
0...9
0...9
0...9,各数位累加和最多不会超过
9
∗
9
=
81
9*9=81
9∗9=81.
所以我们只需要枚举
n
−
100
n-100
n−100到
n
n
n的所有数,验证一下即可.
启示:有时候,题目就已经告诉你正解是什么了,由此要仔细读题,不放过一个字,既是为了能跟快相出正解,也是为了避免一些不必要的读题错误,让此次比赛无憾
代码:
#include <bits/stdc++.h>
using namespace std;
int n, sum = 0, tot = 0;
int a[1000];
int main() {
freopen("num.in","r",stdin);
freopen("num.out","w",stdout);
scanf("%d",&n);
for (int i=max(n-300,1);i<=n;i++) {
int k = 0, j = i;
while (j) {
k = k + j%10;
j=j/10;
}
if (k+i == n) sum++,a[++tot]=i;
}
printf("%d\n",sum);
for (int i=1;i<=tot;i++) printf("%d\n",a[i]);
return 0;
}
T2:组合技能(combo.cpp)
题目描述:
蓝月商城出新技能书了!!
如果古天乐想购买“旋风斩”,则他需要花费
A
A
A元;如果古天乐想买“半月弯刀”,则需要
B
B
B元;如果古天乐两个一起买,则需要
C
C
C元。
蓝月的设计师非常有头脑,每样商品的利润都是相同的。即假设旋风斩和半月弯刀的成本为
a
,
b
a,b
a,b元,则
A
−
a
=
B
−
b
=
C
−
a
−
b
A-a=B-b=C-a-b
A−a=B−b=C−a−b。
给出
A
A
A,
B
B
B,
C
C
C求出利润,数据保证为正数。
格式
输入第一行一个数
T
(
T
<
=
100
)
T(T<=100)
T(T<=100),表示T次询问。
接下来T行,每行三个数
A
,
B
,
C
(
A
,
B
,
C
<
=
2000
)
A,B,C (A,B,C <= 2000)
A,B,C(A,B,C<=2000)
输出T行,每行一个数,表示利润。
Input :
3
275 214 420
6 9 11
199 199 255
Output:
69
4
143
心路历程:
这题十分水,看完题目我很快就得出了结论——
利
润
=
A
+
B
−
C
利润=A+B-C
利润=A+B−C
题目分析:
设利润为
x
x
x
A
−
a
=
B
−
b
=
C
−
a
−
b
A-a=B-b=C-a-b
A−a=B−b=C−a−b
A
−
a
+
B
−
b
=
2
x
,
C
−
a
−
b
=
x
A-a+B-b=2x,C-a-b=x
A−a+B−b=2x,C−a−b=x
A
−
a
+
B
−
b
−
x
=
C
−
a
−
b
A-a+B-b-x=C-a-b
A−a+B−b−x=C−a−b
x
=
A
+
B
−
C
x=A+B-C
x=A+B−C
代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
freopen("combo.in","r",stdin);
freopen("combo.out","w",stdout);
int T;
scanf("%d",&T);
while (T--) {
int a, b, c;
scanf("%d%d%d",&a,&b,&c);
printf("%d\n",a+b-c);
}
}
T3:表面积(surface.cpp)
题目描述:
古天乐在搭积木,积木图可以抽象为一个 n ∗ m n*m n∗m的网格图,其中第 ( i , j ) (i,j) (i,j)的位置有 A i , j A_{i,j} Ai,j个积木。求表面积。
格式:
输入第一行两个数
n
,
m
n,m
n,m,接下来
n
n
n行每行
m
m
m个数,表示
A
i
,
j
A_{i,j}
Ai,j。
输出一个数,表示表面积。
范围:
1
<
=
n
,
m
<
=
100
1<=n,m<=100
1<=n,m<=100
1
<
=
A
i
,
j
<
=
100
1<=A_{i,j}<=100
1<=Ai,j<=100
Input 1:
1 1
1
Output 1:
6
Input 2:
3 3
1 3 4
2 2 3
1 2 4
Output 2 :
60
心路历程:
我也不知道我考试时候怎么想的,满脑浆糊,思路不清就开始写代码了。
于是我就炸了。
题目分析:
我们可将所有木块的总表面积算出来。
然后将重叠的木块的表面积减去,就是我们所要的题目的解。
总面积为
s
u
m
∗
6
sum * 6
sum∗6 (
s
u
m
sum
sum为总积木数)。
对于上下重叠: 重叠的部分面积为
(
A
i
,
j
−
1
)
∗
2
(A_{i,j}-1) * 2
(Ai,j−1)∗2。
对于左右,前后:重叠的部分面积可以通过
f
o
r
for
for循环模拟得出。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 200, M = 200;
int a[N][M];
int n, m;
int f[N+100];
int main() {
freopen("surface.in","r",stdin);
freopen("surface.out","w",stdout);
int sum = 0, ans = 0;
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) {
for (int j=1;j<=m;j++) {
scanf("%d",&a[i][j]);
sum += a[i][j] * 6;
ans += 2 * (a[i][j]-1);
}
}
for (int i=1;i<=n;i++)
for (int j=2;j<=m;j++)
ans += min(a[i][j], a[i][j-1]) * 2;
for (int j=1;j<=m;j++)
for (int i=2;i<=n;i++)
ans += min(a[i][j], a[i-1][j]) * 2;
printf("%d",sum - ans);
}
T4 :红皇后的旅行(redqueen.cpp)
题目描述:
给定一个 n ∗ n n*n n∗n的棋盘,行和列标号为 0 , 1 , 2 , … . , n − 1 0,1,2,….,n-1 0,1,2,….,n−1。在棋盘的 ( i s t a r t , j s t a r t ) (i_{start},j_{start}) (istart,jstart)位置上有一位红皇后,每次红皇后可以往六个方向走,如图所示:
现在红皇后想去
(
i
e
n
d
,
j
e
n
d
)
(i_{end},j_{end})
(iend,jend)点,求最短距离,并且输出一条路径。
显然最短路径有无穷条,请按照以下顺序来搜索:
U
L
,
U
R
,
R
,
L
R
,
L
L
,
L
UL, UR, R, LR, LL, L
UL,UR,R,LR,LL,L。
如果无解,输出
I
m
p
o
s
s
i
b
l
e
Impossible
Impossible
格式:
输入第一行一个数n,第二行四个数,i_start,j_start,i_end,j_end。
输出第一行一个数,最小步数,第二行输出方案。
范围:
5
<
=
n
<
=
200
5<=n<=200
5<=n<=200
0
<
=
i
s
t
a
r
t
,
j
s
t
a
r
t
,
i
e
n
d
,
j
e
n
d
<
=
n
0<=i_{start},j_{start},i_{end},j_{end}<=n
0<=istart,jstart,iend,jend<=n
t
h
e
the
the
s
t
a
r
r
t
i
n
g
starrting
starrting
a
n
d
and
and
e
n
d
i
n
g
ending
ending
p
o
s
i
t
i
o
n
position
position
a
r
e
are
are
d
i
f
f
e
r
e
n
t
different
different.
Input 1:
7
6 6 0 1
Output 1:
4
UL UL UL L
Input 2:
6
5 1 0 5
Output 2:
Impossible
Input 2:
7
0 3 4 3
Output 2:
2
LR LL
心路历程:
这道题很显然就是裸的BFS,看完题目,我就开始码代码了。
但是,我犯了一个致命的错误,对于初始化,我忘记了对开始点的标记。
以至于我的程序一直死循环,45min过去了,我仍然没有改出错误,于是先看下一题。
(我到比赛结束都没有找出错误)
题目分析:
使用BFS持续向外扩展,并同时记录路径和当前步数。
最后,由终点向起始点输出。
启示:当找不到程序错误时,去看看那些微小的地方,说不定,错误就错在那里
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 40010, M = 300;
int fx[20] = {-2,-2,0,2,2,0};
int fy[20] = {-1,1,2,1,-1,-2};
struct egde {
int x, y;
}q[N];
int n, f[M][M];
int h = 0, t = 0;
int sti, stj,edi,edj;
int prei[M][M], prej[M][M], num[M][M], run[M][M];
void write(int x,int y) {
// cout<<prei[x][y]<<' '<<x<<' '<<y<<endl;
if (!prei[x][y]) return;
write(prei[x][y], prej[x][y]);
if (num[x][y] == 0) printf("UL ");
if (num[x][y] == 1) printf("UR ");
if (num[x][y] == 2) printf("R ");
if (num[x][y] == 3) printf("LR ");
if (num[x][y] == 4) printf("LL ");
if (num[x][y] == 5) printf("L ");
}
void bfs() {
q[++t].x = sti;
q[t].y = stj;
f[sti][stj] = 1;
while (t>=h) {
int nowi = q[++h].x, nowj = q[h].y;
for (int i=0;i<=5;i++) {
int x = nowi + fx[i], y= nowj + fy[i];
if (x <= 0 || y > n || y <= 0 || x > n) continue;
if (!f[x][y]) {
f[x][y] = 1;
q[++t].x = x;
q[t].y = y;
prei[x][y] = nowi, prej[x][y] = nowj;
num[x][y] = i, run[x][y] = run[nowi][nowj] + 1;
if (x == edi && edj == y) {
printf("%d\n",run[x][y]);
write(edi,edj);
return;
}
}
}
}
printf("Impossible");
}
int main() {
freopen("redqueen.in","r",stdin);
freopen("redqueen.out","w",stdout);
scanf("%d%d%d%d%d",&n,&sti,&stj,&edi,&edj);
n+=1;sti+=1;stj+=1;edi+=1;edj+=1;
bfs();
return 0;
}
T5:构造序列(construct.cpp)
题目描述:
有一个长度为
n
n
n的序列
A
A
A,其中
A
[
1
]
=
1
,
A
[
n
]
=
x
,
A
[
2
…
n
−
1
]
A[1]=1,A[n]=x,A[2…n-1]
A[1]=1,A[n]=x,A[2…n−1]可以是
1
1
1至
k
k
k间任意一个正整数。求有多少个不同的序列,使得相邻两个数不同。
答案
1
0
9
+
7
10^9+7
109+7取模。
格式:
输入共一行,包含三个数,
n
,
k
,
x
n,k,x
n,k,x。
输出一个数,表示答案。
范围:
3
<
=
n
<
=
1
0
5
3<=n<=10^5
3<=n<=105
2
<
=
k
<
=
1
0
5
2<=k<=10^5
2<=k<=105
1
<
=
x
<
=
k
1<=x<=k
1<=x<=k
Input 1:
4 3 2
Output 1:
3
心路历程:
先考虑如果没有
A
[
1
]
A[1]
A[1]和
A
[
n
]
A[n]
A[n]的限制,怎么办?
很显然,答案就是
k
∗
(
k
−
1
)
(
n
−
1
)
k*(k-1)^{(n-1)}
k∗(k−1)(n−1)。
因为这道题很显然是递推,所以我就从各种方面去尝试寻找突破口。
时间好快,
1
h
1h
1h
30
m
i
n
30min
30min过去了,我仍然没有退出来。
比赛即将结束…
题目分析:
我们设
f
i
,
j
f_{i,j}
fi,j为在前i个空中,第
i
i
i个空填
j
j
j的方案数。
显然
f
i
,
j
=
f
i
−
1
,
1
+
f
i
−
1
,
2
+
f
i
−
1
,
3
+
.
.
.
.
+
f
i
−
1
,
k
−
f
i
−
1
,
j
f_{i,j}=f_{i-1,1}+f_{i-1,2}+f_{i-1,3}+....+f_{i-1,k}-f_{i-1,j}
fi,j=fi−1,1+fi−1,2+fi−1,3+....+fi−1,k−fi−1,j;
因为我们只需要
f
i
,
x
f_{i,x}
fi,x,我们就可简化为
f
i
=
f
i
−
1
∗
(
k
−
1
)
f_{i}=f_{i-1} *(k-1)
fi=fi−1∗(k−1)。
我们再设
f
x
[
i
]
fx[i]
fx[i]为第i个数为x时的方案数。
那就有了以下式子:
f
x
[
i
]
=
f
[
i
−
1
]
−
f
x
[
i
−
1
]
fx[i]=f[i-1]-fx[i-1]
fx[i]=f[i−1]−fx[i−1]。
那么
f
x
[
n
]
fx[n]
fx[n]就是我们需要的答案。