比赛开始后我把五题都看了一遍,第四题显然是BFS 码量会稍微大一点 而第五题我已经有了一点思路 所以我的做题顺序是1,2,3,5,4
T1 :
题意描述:
给出一个正整数
n
n
n,现在问存在多少个
x
x
x,使得
x
x
x 在十进制下的每一位之和加上
x
x
x 等于
n
n
n
样例输入:
21 21 21
样例输出:
1
1
1
15
15
15
(第一行输出个数,之后每行一个
x
x
x(从小到大),无符合的
x
x
x就输出
0
0
0)
思路:
最开始只想到O(n)的暴力,想着先写出来,为了尽量优化,就思考知道
i
i
i的值 怎么直接计算
i
+
1
i+1
i+1的值
i
+
1
i+1
i+1的值应该等于
i
i
i的值+2 而当
i
+
1
i+1
i+1为整十数时会有变化 于是有了以下代码
for(int i=1;i<n;i++) {
if (i%1000000000==0) s-=81;
else if (i%100000000==0) s-=72;
else if (i%10000000==0) s-=63;
else if (i%1000000==0) s-=54;
else if (i%100000==0) s-=45;
else if (i%10000==0) s-=36;
else if (i%1000==0) s-=27;
else if (i%100==0) s-=18;
else if (i%10==0) s-=9;
s+=2;
if (s==n) f[++t]=i;
}
然后为了测试这段代码到底对不对 我尝试了很多个数 然后发现答案与 n n n 都很相似 然后。。。
正解:
一个数x的值 分为其本身和各数位之和 而各数位之和不会超过
81
81
81,所以从
n
−
100
n-100
n−100枚举
n
n
n再统计就好了
代码如下:
scanf("%d",&n);
int s=max(n-200,0),k=max(n-200,0);
while (k>0) {
s+=k%10;
k/=10;
}
for(int i=max(n-200+1,1);i<n;i++) {
if (i%100==0) s-=18;
else if (i%10==0) s-=9;
s+=2;
if (s==n) f[++t]=i;
}
cout<<t<<endl;
for(int i=1;i<=t;i++) printf("%d\n",f[i]);
用时 20 m i n 20min 20min
T2 :
题目描述:
已知
A
−
a
=
B
−
b
=
C
−
a
−
b
A-a=B-b=C-a-b
A−a=B−b=C−a−b 输入
A
,
B
,
C
A,B,C
A,B,C 求
A
−
a
A-a
A−a
数
据
有
多
组
数据有多组
数据有多组
样例输入:
3
3
3
275
275
275
214
214
214
420
420
420
6
6
6
9
9
9
11
11
11
199
199
199
199
199
199
255
255
255
(第一行为数据组数,之后每行三个整数,分别为 A , B , C A,B,C A,B,C)
样例输出:
69
69
69
4
4
4
143
143
143
思路:
这。。 a + b a+b a+b的翻版。。全场最水的题
正解:
解个方程 即可得 A − a = A + B − C A-a=A+B-C A−a=A+B−C 代码如下:
scanf("%d",&T);
for(int i=1;i<=T;i++) {
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
printf("%d\n",a+b-c);
}
用时 2 m i n 2min 2min
T3 :
题面描述:
一个
H
∗
W
H*W
H∗W的网格图,第
(
i
,
j
)
(i,j)
(i,j)的位置有
A
[
i
]
[
j
]
A[i][j]
A[i][j]个积木。求表面积。
样例输入1:
1
1
1
1
1
1
1
1
1
(第一行为 H , W H,W H,W,之后 H H H行,每行 W W W个整数,为 A [ i ] [ j ] A[i][j] A[i][j])
样例输出1:
6 6 6
样例输入2:
3
3
3
3
3
3
1
1
1
3
3
3
4
4
4
2
2
2
2
2
2
3
3
3
1
1
1
2
2
2
4
4
4
样例输出2:
60 60 60
思路:
最开始想的是六视图面积之和,之后想到中间会有凹下去的地方,那就一格格计算表面积,与相邻的几个比较,高出部分即露出面积。对于每一格,如果 A [ i ] [ j ] A[i][j] A[i][j]不为0,则答案+2(上下面积)
正解 :
与上诉同,对于边上的那些格子由于超出边界的
A
[
i
]
[
j
]
A[i][j]
A[i][j]值为零,因此不影响答案。
代码如下:
scanf("%d%d",&n,&m);
int sum=0;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
scanf("%d",&a[i][j]);
sum+=(a[i][j]!=0);
}
}
sum<<=1;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
for(int x=0;x<4;x++) {
int l=i+dx[x],r=j+dy[x];
sum+=(a[i][j]-a[l][r])*(a[i][j]>a[l][r]);
}
}
}
用时 15 m i n 15min 15min
T5 :
题面描述 :
有一个长度为
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取模。
样例输入:
4 4 4 3 3 3 2 2 2
(输入共一行,依次为 n , k , x n,k,x n,k,x)
样例输出:
3 3 3
思路 :
第一眼想到的是暴力
f
i
,
j
f_{i,j}
fi,j表示填前
i
i
i个数字,第i个数字为j的总方案数
那么转移方程为
f
i
,
j
f_{i,j}
fi,j=
f
i
−
1
,
1
+
f
i
−
1
,
2
+
.
.
.
+
f
i
−
1
,
k
−
f
i
−
1
,
j
f_{i-1,1}+f_{i-1,2}+...+f_{i-1,k}-f_{i-1,j}
fi−1,1+fi−1,2+...+fi−1,k−fi−1,j
目标为
f
n
,
x
f_{n,x}
fn,x
接着考虑优化,由于我们只关注
f
i
,
x
f_{i,x}
fi,x
因此我们可以把转移方程变成两部分
f
i
−
1
,
1
+
f
i
−
1
,
2
+
.
.
.
+
f
i
−
1
,
k
f_{i-1,1}+f_{i-1,2}+...+f_{i-1,k}
fi−1,1+fi−1,2+...+fi−1,k和
f
i
−
1
,
x
f_{i-1,x}
fi−1,x
我们让
d
p
i
=
f
i
,
1
+
f
i
,
2
+
.
.
.
+
f
i
,
k
,
F
i
=
f
i
,
x
dp_{i}=f_{i,1}+f_{i,2}+...+f_{i,k},F_i=f_{i,x}
dpi=fi,1+fi,2+...+fi,k,Fi=fi,x
那么
F
i
=
d
p
i
−
F
i
−
1
F_i=dp_i-F_{i-1}
Fi=dpi−Fi−1
然后考虑
d
p
i
dp_i
dpi的转移
d
p
i
=
f
i
,
1
+
f
i
,
2
+
.
.
.
+
f
i
,
k
=
k
∗
(
f
i
−
1
,
1
+
f
i
−
1
,
2
+
.
.
.
+
f
i
−
1
,
k
)
−
(
f
i
−
1
,
1
+
f
i
−
1
,
2
+
.
.
.
+
f
i
−
1
,
k
−
f
i
−
1
,
j
)
=
(
k
−
1
)
∗
(
f
i
−
1
,
1
+
f
i
−
1
,
2
+
.
.
.
+
f
i
−
1
,
k
−
f
i
−
1
,
j
)
=
(
k
−
1
)
∗
d
p
i
−
1
dp_{i}=f_{i,1}+f_{i,2}+...+f_{i,k}=k*(f_{i-1,1}+f_{i-1,2}+...+f_{i-1,k})-(f_{i-1,1}+f_{i-1,2}+...+f_{i-1,k}-f_{i-1,j})=(k-1)*(f_{i-1,1}+f_{i-1,2}+...+f_{i-1,k}-f_{i-1,j})=(k-1)*dp_{i-1}
dpi=fi,1+fi,2+...+fi,k=k∗(fi−1,1+fi−1,2+...+fi−1,k)−(fi−1,1+fi−1,2+...+fi−1,k−fi−1,j)=(k−1)∗(fi−1,1+fi−1,2+...+fi−1,k−fi−1,j)=(k−1)∗dpi−1
正解 :
按上述方法进行转移
初始状态
d
p
[
1
]
=
1
dp[1]=1
dp[1]=1 如果
x
=
1
x=1
x=1则
F
[
1
]
=
1
F[1]=1
F[1]=1否则为
0
0
0
目标状态
F
[
n
]
F[n]
F[n]
代码如下:
注:代码中
f
i
f_i
fi为
d
p
i
dp_i
dpi,
f
x
i
fx_i
fxi为
F
i
F_i
Fi,
m
o
=
1
0
9
+
7
mo=10^9+7
mo=109+7
scanf("%lld%lld%lld",&n,&k,&x);
f[2]=k-1;
for(int i=3;i<n;i++) {
f[i]=f[i-1]*(k-1)%mo;
}
if (x==1) fx[2]=0;
else fx[2]=1;
for(int i=3;i<=n;i++) {
fx[i]=(f[i-1]-fx[i-1]+mo)%mo;
}
printf("%lld",fx[n]);
用时 25 m i n 25min 25min
T4 :
题面描述 :
给定一个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
样例输入:
7
7
7
6
6
6
6
6
6
0
0
0
1
1
1
(输入共l两行,第一行为一个整数 n n n,第二行为四个整数,依次为 i s t a r t , j s t a r t , i e n d , j e n d i_{start},j_{start},i_{end},j_{end} istart,jstart,iend,jend)
样例输出:
4
4
4
UL UL UL L
(输出第一行为最短步数,第二行为方案)
思路 :
一眼
B
F
S
BFS
BFS,从起点开始不断向六个方向扩展就完事了
唯一要注意的就是边界为0~n-1
正解 :
直接上代码:
inline void bfs() {
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
l[i][j]=r[i][j]=-(1<<30);
}
}
int t=1,h=1,k=0;
q[t].x=it,q[t].y=jt;
vis[it][jt]=1;
while (h<=t) {
k++;
int temp=t;
for(int i=h;i<=temp;i++) {
for(int j=0;j<6;j++) {
int x=q[i].x+dx[j],y=q[i].y+dy[j];
if (x<0 || y<0 || x>=n || y>=n) continue;
if (!vis[x][y]) {
q[++t].x=x,q[t].y=y;
vis[x][y]=1;
l[x][y]=q[i].x;
r[x][y]=q[i].y;
num[x][y]=j;
if (x == id && y == jd) {
printf("%d\n",k);
putans(x,y);
return ;
}
}
}
}
h=temp+1;
}
printf("Impossible");
}
inline void putans(int x,int y) {
if (l[x][y]<0) return ;
putans(l[x][y],r[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");
if (!(x == id && y == jd)) printf(" ");
}
用时 35 m i n 35min 35min
总结:
此次模拟赛总体感觉普及减难度,较水,导致我写完+检查完还有一个半小时。。。
但是即使是水题,细节依然是很重要的,一个小小的不注意可能就会要你一个小时,此时心态要好,再看看题,打几个表,说不定就能解决。(点名zcc)
补充:T5plus
如果有 t o t tot tot个格子数字是固定的怎么办?? T o t < = N Tot<=N Tot<=N
思路简述:
将连续的没有被固定的格子按 T 5 T5 T5方法计算,最后将所有所得值相乘即为答案