2019.5.31模拟赛总结加题解

比赛开始后我把五题都看了一遍,第四题显然是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 n100枚举 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 Aa=Bb=Cab 输入 A , B , C A,B,C A,B,C A − a A-a Aa
数 据 有 多 组 数据有多组

样例输入:

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 Aa=A+BC 代码如下:

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 HW的网格图,第 ( 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]=xA[2n1]可以是 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} fi1,1+fi1,2+...+fi1,kfi1,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} fi1,1+fi1,2+...+fi1,k f i − 1 , x f_{i-1,x} fi1,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=dpiFi1
然后考虑 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(fi1,1+fi1,2+...+fi1,k)(fi1,1+fi1,2+...+fi1,kfi1,j)=(k1)(fi1,1+fi1,2+...+fi1,kfi1,j)=(k1)dpi1

正解 :

按上述方法进行转移
初始状态 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,.,n1。在棋盘的 ( 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 &lt; = N Tot&lt;=N Tot<=N

思路简述:

将连续的没有被固定的格子按 T 5 T5 T5方法计算,最后将所有所得值相乘即为答案


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值