洛谷题单——数组篇

题目列表:

1.小鱼比可爱

2.小鱼的数字游戏

3.冰雹猜想

4.校门外的树

5.旗鼓相当的对手

6.工艺品制作

7.彩票摇奖

8.神奇的幻方

9.显示屏

10.梦中的统计

11.珠心算测验

12.爱与愁的心痛

13.Bovine Bones G

14.开灯

15.蛇形方阵

16.杨辉三角

17.插火把

18.压缩技术

19.压缩技术(续集版)

20.方块转换

(以下代码都是满分通过)

1.小鱼比可爱

题目描述

人比人,气死人;鱼比鱼,难死鱼。小鱼最近参加了一个“比可爱”比赛,比的是每只鱼的可爱程度。参赛的鱼被从左到右排成一排,头都朝向左边,然后每只鱼会得到一个整数数值,表示这只鱼的可爱程度,很显然整数越大,表示这只鱼越可爱,而且任意两只鱼的可爱程度可能一样。由于所有的鱼头都朝向左边,所以每只鱼只能看见在它左边的鱼的可爱程度,它们心里都在计算,在自己的眼力范围内有多少只鱼不如自己可爱呢。请你帮这些可爱但是鱼脑不够用的小鱼们计算一下。

输入格式

第一行输入一个整数 n,表示鱼的数目。

第二行内输入 n个整数,用空格间隔,依次表示从左到右每只小鱼的可爱程度。

输出格式

行内输出 n 个整数,用空格间隔,依次表示每只小鱼眼中有多少只鱼不如自己可爱。

输入输出样例

输入

6
4 3 0 5 1 2

输出 

0 0 0 3 1 2

说明/提示

对于 100% 的数据,n≤100。

分析:

思路1:一一遍历

思路2:利用树状数组求左边比自己小的数的个数

思路1的代码:

#include<iostream>
using namespace std;
const int N = 110;
int n;
long long a[N];
int main(){
	cin >> n;
	for(int i = 0;i < n;i++){
		cin >> a[i];
		int ans = 0;
		for(int j = i-1;j >= 0;j--){
			if(a[j] < a[i]){
				ans++;
			}
		} 
		cout << ans << " ";
	}
	return 0;
} 

思路2的代码:

#include<iostream>
using namespace std;
const int N = 110;
int n; 
long long a[N];
int lowbit(int x){ 
	return x&(-x);
}
long long query(long long c[],int x){
	long long sum = 0;
	while(x){
		sum += c[x];
		x -= lowbit(x);
	}
	return sum;
}
void update(long long c[],int Maxn,int x,int v){
	while(x <= Maxn){
		c[x] += v;
		x += lowbit(x);
	}
}
int main(){
	cin >> n;
	long long Maxn = 0;
	for(int i = 0;i < n;i++){
		cin >> a[i];
		Maxn = max(Maxn,a[i]);
 	}
 	long long c[N] = {0}; 
	for(int i = 0;i < n;i++){
		update(c,Maxn+1,a[i]+1,1);
		cout << query(c,a[i])<< " ";
	}
	return 0;
}

2.小鱼的数字游戏

题目描述

小鱼最近被要求参加一个数字游戏,要求它把看到的一串数字 ai​(长度不一定,以 0 结束),记住了然后反着念出来(表示结束的数字 0 就不要念出来了)。这对小鱼的那点记忆力来说实在是太难了,你也不想想小鱼的整个脑袋才多大,其中一部分还是好吃的肉!所以请你帮小鱼编程解决这个问题。

输入格式

一行内输入一串整数,以 0 结束,以空格间隔。

输出格式

一行内倒着输出这一串整数,以空格间隔。

输入输出样例

输入

3 65 23 5 34 1 30 0

输出 

30 1 34 5 23 65 3

说明/提示

数据规模与约定

对于 100% 的数据,保证 0≤ai​≤2^{31}-1,数字个数不超过100。

代码: 

#include<iostream>
using namespace std;
const int N = 110;
long long a[N];
int main(){
	long long x;
	int i = 0;
	while(1){
		cin >> x;
		if(x == 0){
			break;
		}
		a[i++] = x;
	}
	for(int j = i-1;j >= 0;j--){
		cout << a[j] << " ";
	}
	return 0;
}

3.冰雹猜想

题目描述

给出一个正整数 n(n≤100),然后对这个数字一直进行下面的操作:如果这个数字是奇数,那么将其乘 3 再加 1,否则除以 2。经过若干次循环后,最终都会回到 1。经过验证很大的数字(7×10^{11})都可以按照这样的方式比变成 1,所以被称为“冰雹猜想”。例如当 n是 20,变化的过程是 [20, 10, 5, 16, 8, 4, 2, 1]。

根据给定的数字,验证这个猜想,并从最后的 1 开始,倒序输出整个变化序列。

输入格式

输出格式

输入输出样例

输入 

20

输出

1 2 4 8 16 5 10 20 

分析:

思路1:数组存储,逆序输出

思路2:递归

思路3:栈

思路1的代码: 

#include<iostream>
using namespace std;
const int N = 110;
int a[N];
int main(){
	long long n;
	cin >> n;
	a[0] = n;
	int i = 1;
	while(n!=1){
		if(n%2!=0){
			n=n*3+1;
		}else{
			n/=2;
		}
		a[i++] = n;
	}
	for(int j = i-1;j >= 0;j--){
		cout << a[j] << " ";
	}
	return 0;
}

思路2的代码:

#include<iostream>
using namespace std;
void solve(int n){
	if(n == 1){
		cout << 1 << " ";
		return;
	}
	if(n%2!=0){
		solve(n*3+1);
	}else{
		solve(n/2);
	}
	cout << n << " ";
}
int main(){
	long long n;
	cin >> n;
	solve(n);
	return 0;
}

思路3的代码:

#include<iostream>
#include<stack>
using namespace std;
int main(){
	long long n;
	cin >> n;
	stack<int> s;
	s.push(n);
	while(n!=1){
		if(n%2!=0){
			n=n*3+1;
		}else{
			n/=2;
		}
		s.push(n);
	}
	while(!s.empty()){
		cout << s.top() << " ";
		s.pop();
	} 
	return 0;
}

4.校门外的树

题目描述

某校大门外长度为 l 的马路上有一排树,每两棵相邻的树之间的间隔都是 1 米。我们可以把马路看成一个数轴,马路的一端在数轴 0 的位置,另一端在 l 的位置;数轴上的每个整数点,即 0,1,2,…,l,都种有一棵树。

由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。

输入格式

第一行有两个整数,分别表示马路的长度 l 和区域的数目 m。

接下来 m 行,每行两个整数 u, v,表示一个区域的起始点和终止点的坐标。

输出格式

输出一行一个整数,表示将这些树都移走后,马路上剩余的树木数量。

输入输出样例

输入

500 3
150 300
100 200
470 471

输出

298

说明/提示

【数据范围】

  • 对于20% 的数据,保证区域之间没有重合的部分。
  • 对于100% 的数据,保证 1≤l≤10^{4},1≤m≤100,0≤u≤v≤l。

分析:

思路1:利用bool数组,被砍设为true,最后统计false的个数

思路2:利用珂朵莉树进行区间的统一赋值 

思路1的代码:

#include<iostream>
using namespace std;
const int MAX_L = 1e4+10;
int l,m;
bool a[MAX_L];
int main(){
	cin >> l >> m;
	int u,v;
	for(int i = 0;i < m;i++){
		cin >> u >> v;
		for(int j = u;j <= v;j++){
			a[j] = true; 
		}
	}
	int ans = 0;
	for(int i = 0;i <= l;i++){
		if(!a[i]){
			ans++;
		}
	}
	cout << ans;
	return 0;
}

思路2的代码:

#include<iostream>
#include<set>
using namespace std;
int l,m;
struct node{
	int l,r;//区间的左右边界
	mutable bool v;//区间内的数值的类型 
	node(int L,int R = -1,bool V = false):l(L),r(R),v(V) {}
	inline bool operator<(const node& o) const{
		return l < o.l;
	}
}; 
typedef set<node>::iterator IT;
set<node> s;
//接收一个整数pos,会找到包含pos的区间,将其拆分为[l,pos)和[pos,r)两个区间,并返回指向后者的迭代器 
IT split(int pos){
	IT it = s.lower_bound(node(pos));
	if(it != s.end() && it->l == pos){
		return it;
	}
	--it;
	int L = it->l,R = it->r,V = it->v;
	s.erase(it);//先删除[l,r) 
	s.insert(node(L,pos-1,V));//插入[l,pos) 
	return s.insert(node(pos,R,V)).first;//插入[pos,r)并返回地址 
} 
//珂朵莉树在进行求取区间左右端点操作时,必须先 split 右端点,再 split 左端点 
//区间赋值(把范围内的节点全部删除,然后换上新的打包节点)
void assign(int l,int r,bool v){
	IT itr = split(r+1),itl = split(l);
	s.erase(itl,itr);
	s.insert(node(l,r,v));
} 
int count(int l,int r){
	int res = 0;
	IT itr = split(r+1),itl = split(l);
	for(;itl!=itr;itl++){
		res += itl->v? itl->r-itl->l+1 : 0; 
	}
	return res;
} 
int main(){
	cin >> l >> m;
	s.insert(node(0,l,true));
	int u,v;
	for(int i = 0;i < m;i++){
		cin >> u >> v;
		assign(u,v,false);
	}
	cout << count(0,l);
	return 0;
}

5.旗鼓相当的对手

题目描述

现有 N(N≤1000) 名同学参加了期末考试,并且获得了每名同学的信息:语文、数学、英语成绩(均为不超过 150 的自然数)。如果某对学生 <i,j> 的每一科成绩的分差都不大于 5,且总分分差不大于 10,那么这对学生就是“旗鼓相当的对手”。现在想知道这些同学中,有几对“旗鼓相当的对手”?同样一个人可能会和其他好几名同学结对。

输入格式

第一行一个正整数 N。

接下来 N 行,每行三个整数,其中第 i 行表示第 i 名同学的语文、数学、英语成绩。最先读入的同学编号为 1。

输出格式

输出一个个整数,表示“旗鼓相当的对手”的对数。

输入输出样例

输入

3
90 90 90
85 95 90
80 100 91

输出

2

代码:

#include<iostream>
#include<cmath>
using namespace std;
const int MAX_N = 1010;
struct score{
	int c,m,e;
	int sum;
}a[MAX_N];
int main(){
	int N;
	cin >> N;
	int ans = 0;
	for(int i = 0;i < N;i++){
		cin >> a[i].c >> a[i].m >> a[i].e;
		a[i].sum = a[i].c+a[i].m+a[i].e;
		for(int j = i-1;j >= 0;j--){
			if(abs(a[i].c-a[j].c) <= 5){
				if(abs(a[i].m-a[j].m) <= 5){
					if(abs(a[i].e-a[j].e) <= 5){
						if(abs(a[i].sum-a[j].sum) <= 10){
							ans++;
						}
					}
				}
			}
		}
	}
	cout << ans;
	return 0;
}

6.工艺品制作

题目描述

现有一个长宽高分别为 w,x,h(1≤w,x,h≤20) 组成的实心玻璃立方体,可以认为是由1×1×1 的数个小方块组成的,每个小方块都有一个坐标 (i,j,k)。现在需要进行 q(q≤100) 次切割。每次切割给出 (x1​,y1​,z1​),(x2​,y2​,z2​) 这 6 个参数,保证x1​≤x2​,y1​≤y2​,z1​≤z2​;每次切割时,使用激光工具切出一个立方体空洞,空洞的壁平行于立方体的面,空洞的对角点就是给出的切割参数的两个点。

换句话说,所有满足x1​≤i≤x2​,y1​≤j≤y2​,z1​≤k≤z2​ 的小方块(i,j,k) 的点都会被激光蒸发。例如有一个 4×4×4 的大方块,其体积为 64;给出参数 (1,1,1),(2,2,2) 时,中间的 8 块小方块就会被蒸发,剩下 56 个小方块。现在想知道经过所有切割操作后,剩下的工艺品还剩下多少格小方块的体积?

输入格式

第一行三个正整数 w,x,h。

第二行一个正整数 q。

接下来q 行,每行六个整数(x1​,y1​,z1​),(x2​,y2​,z2​)

输出格式

输出一个整数表示答案。

输入输出样例

输入

4 4 4
1
1 1 1 2 2 2

输出 

56

代码:

#include<iostream>
using namespace std;
const int N = 25;
bool a[N][N][N];
int main(){
	int w,x,h,q;
	cin >> w >> x >> h >> q;
	int x1,x2,y1,y2,z1,z2;
	for(int i = 0;i < q;i++){
		cin >> x1 >> y1 >> z1 >> x2 >> y2 >> z2;
		for(int i = x1;i <= x2;i++)
			for(int j = y1;j <= y2;j++)
				for(int k = z1;k <= z2;k++)
					a[i][j][k] = true;
	}
	int ans = 0;
	for(int i = 1;i <= w;i++)
		for(int j = 1;j <= x;j++)
			for(int k = 1;k <= h;k++)
				if(!a[i][j][k]) ans++;

	cout << ans;
	return 0;
}

 

7.彩票摇奖

题目描述

为了丰富人民群众的生活、支持某些社会公益事业,北塔市设置了一项彩票。该彩票的规则是:

  1. 每张彩票上印有 7 个各不相同的号码,且这些号码的取值范围为 1∼33。
  2. 每次在兑奖前都会公布一个由七个各不相同的号码构成的中奖号码。
  3. 共设置 7 个奖项,特等奖和一等奖至六等奖。

兑奖规则如下:

  • 特等奖:要求彩票上 7 个号码都出现在中奖号码中。
  • 一等奖:要求彩票上有 6 个号码出现在中奖号码中。
  • 二等奖:要求彩票上有 5 个号码出现在中奖号码中。
  • 三等奖:要求彩票上有 4 个号码出现在中奖号码中。
  • 四等奖:要求彩票上有 3 个号码出现在中奖号码中。
  • 五等奖:要求彩票上有 2 个号码出现在中奖号码中。
  • 六等奖:要求彩票上有 1 个号码出现在中奖号码中。

注:兑奖时并不考虑彩票上的号码和中奖号码中的各个号码出现的位置。例如,中奖号码为 23 31 1 14 19 17 18,则彩票 12 8 9 23 1 16 7 由于其中有两个号码(23 和 1)出现在中奖号码中,所以该彩票中了五等奖。

现已知中奖号码和小明买的若干张彩票的号码,请你写一个程序帮助小明判断他买的彩票的中奖情况。

输入格式

输入的第一行只有一个自然数 n,表示小明买的彩票张数;

第二行存放了 7 个介于 1 和 33之间的自然数,表示中奖号码;

在随后的 n行中每行都有 7 个介于 1 和 33之间的自然数,分别表示小明所买的 n 张彩票。

输出格式

依次输出小明所买的彩票的中奖情况(中奖的张数),首先输出特等奖的中奖张数,然后依次输出一等奖至六等奖的中奖张数。

输入输出样例

输入 

2
23 31 1 14 19 17 18
12 8 9 23 1 16 7
11 7 10 21 2 9 31

输出

0 0 0 0 0 1 1

说明/提示

数据规模与约定

对于 100% 的数据,保证 1≤n<1000。

分析:

在1~33中把中奖号码的7个数记为1,其余数为0

遍历每张彩票的7个数,如果该号码是中奖号码,+1

代码:

#include<iostream>
using namespace std;
int n;
int s[34],p[7];
int main(){
	cin >> n;
	int k;
	for(int i = 0;i < 7;i++){
		cin >> k;
		s[k] = 1;
	}
	for(int i = 0;i < n;i++){
		int cnt = 0;
		for(int j = 0;j < 7;j++){
			cin >> k;
			cnt += s[k];
		}
		p[7-cnt]++;
	}
	for(int i = 0;i < 7;i++){
		cout << p[i] << " ";
	}
	return 0;
}

 

 8.神奇的幻方

题目描述

幻方是一种很神奇的 N∗N 矩阵:它由数字1,2,3,⋯⋯,N×N 构成,且每行、每列及两条对角线上的数字之和都相同。

当 N 为奇数时,我们可以通过下面的方法构建一个幻方:

首先将 1 写在第一行的中间。

之后,按如下方式从小到大依次填写每个数 K(K=2,3,⋯,N×N) :

  1. 若(K−1) 在第一行但不在最后一列,则将 K 填在最后一行, (K-1) 所在列的右一列;
  2. 若 (K−1) 在最后一列但不在第一行,则将 K 填在第一列, (K-1) 所在行的上一行;
  3. 若 (K−1) 在第一行最后一列,则将 K 填在 (K−1) 的正下方;
  4. 若 (K−1) 既不在第一行,也不在最后一列,如果 (K-1)(K−1) 的右上方还未填数,则将 K 填在 (K−1) 的右上方,否则将 K 填在 (K−1) 的正下方。

现给定 N ,请按上述方法构造 N×N 的幻方。

输入格式

一个正整数 N ,即幻方的大小。

输出格式

共 N 行 ,每行 N个整数,即按上述方法构造出的 N×N 的幻方,相邻两个整数之间用单空格隔开。

输入输出样例

输入 

3

输出

8 1 6
3 5 7
4 9 2

输入

25

输出 

327 354 381 408 435 462 489 516 543 570 597 624 1 28 55 82 109 136 163 190 217 244 271 298 325
353 380 407 434 461 488 515 542 569 596 623 25 27 54 81 108 135 162 189 216 243 270 297 324 326
379 406 433 460 487 514 541 568 595 622 24 26 53 80 107 134 161 188 215 242 269 296 323 350 352
405 432 459 486 513 540 567 594 621 23 50 52 79 106 133 160 187 214 241 268 295 322 349 351 378
431 458 485 512 539 566 593 620 22 49 51 78 105 132 159 186 213 240 267 294 321 348 375 377 404
457 484 511 538 565 592 619 21 48 75 77 104 131 158 185 212 239 266 293 320 347 374 376 403 430
483 510 537 564 591 618 20 47 74 76 103 130 157 184 211 238 265 292 319 346 373 400 402 429 456
509 536 563 590 617 19 46 73 100 102 129 156 183 210 237 264 291 318 345 372 399 401 428 455 482
535 562 589 616 18 45 72 99 101 128 155 182 209 236 263 290 317 344 371 398 425 427 454 481 508
561 588 615 17 44 71 98 125 127 154 181 208 235 262 289 316 343 370 397 424 426 453 480 507 534
587 614 16 43 70 97 124 126 153 180 207 234 261 288 315 342 369 396 423 450 452 479 506 533 560
613 15 42 69 96 123 150 152 179 206 233 260 287 314 341 368 395 422 449 451 478 505 532 559 586
14 41 68 95 122 149 151 178 205 232 259 286 313 340 367 394 421 448 475 477 504 531 558 585 612
40 67 94 121 148 175 177 204 231 258 285 312 339 366 393 420 447 474 476 503 530 557 584 611 13
66 93 120 147 174 176 203 230 257 284 311 338 365 392 419 446 473 500 502 529 556 583 610 12 39
92 119 146 173 200 202 229 256 283 310 337 364 391 418 445 472 499 501 528 555 582 609 11 38 65
118 145 172 199 201 228 255 282 309 336 363 390 417 444 471 498 525 527 554 581 608 10 37 64 91
144 171 198 225 227 254 281 308 335 362 389 416 443 470 497 524 526 553 580 607 9 36 63 90 117
170 197 224 226 253 280 307 334 361 388 415 442 469 496 523 550 552 579 606 8 35 62 89 116 143
196 223 250 252 279 306 333 360 387 414 441 468 495 522 549 551 578 605 7 34 61 88 115 142 169
222 249 251 278 305 332 359 386 413 440 467 494 521 548 575 577 604 6 33 60 87 114 141 168 195
248 275 277 304 331 358 385 412 439 466 493 520 547 574 576 603 5 32 59 86 113 140 167 194 221
274 276 303 330 357 384 411 438 465 492 519 546 573 600 602 4 31 58 85 112 139 166 193 220 247
300 302 329 356 383 410 437 464 491 518 545 572 599 601 3 30 57 84 111 138 165 192 219 246 273
301 328 355 382 409 436 463 490 517 544 571 598 625 2 29 56 83 110 137 164 191 218 245 272 299

说明/提示

对于100%的数据,对于全部数据, 1≤N≤39 且 N 为奇数。

分析:

这是借鉴一位大佬写的代码(不得不说,太牛啦!!!果然数学是一切的根源)

将该矩阵上下相接(即第一行和最后一行相接),左右相接(即第一列和最后一列相接),然后从第一行中点开始,把每一个下面的数

放到“右上角”,若右上角有数,则放到正下方。

代码:

#include<iostream>
using namespace std;
int a[40][40];
int main(){
	int N;
	cin >> N;
	int x = 0,y = N/2;
	for(int i = 1;i <= N*N;i++){
		a[x][y] = i;
		if(a[(x+N-1)%N][(y+1)%N] == 0){
			x = (x+N-1)%N;
			y = (y+1)%N;
		}else{
			x = (x+1)%N;
		}
	}
	for(int i = 0;i < N;i++){
		for(int j = 0;j < N;j++){
			cout << a[i][j] << " ";
		}
		cout << endl;
	}
	return 0;
}

 

9.显示屏

题目描述

液晶屏上,每个阿拉伯数字都是可以显示成 5x3 的点阵的(其中 X 表示亮点,. 表示暗点)。现在给出数字位数(不超过 100)和一串数字,要求输出这些数字在显示屏上的效果。数字的显示方式如同样例输出,注意每个数字之间都有一列间隔。

输入格式

输出格式

输入输出样例

输入

10
0123456789

输出

XXX...X.XXX.XXX.X.X.XXX.XXX.XXX.XXX.XXX
X.X...X...X...X.X.X.X...X.....X.X.X.X.X
X.X...X.XXX.XXX.XXX.XXX.XXX...X.XXX.XXX
X.X...X.X.....X...X...X.X.X...X.X.X...X
XXX...X.XXX.XXX...X.XXX.XXX...X.XXX.XXX

分析:

打表 

代码:

#include<iostream>
#include<string>
using namespace std;
char a[10][5][3]=
{
	{//0
		'X','X','X',
		'X','.','X',
		'X','.','X',
		'X','.','X',
		'X','X','X',
	},
	{//1
		'.','.','X',
		'.','.','X',
		'.','.','X',
		'.','.','X',
		'.','.','X',
	},
	{//2
		'X','X','X',
		'.','.','X',
		'X','X','X',
		'X','.','.',
		'X','X','X',
	},
	{//3
		'X','X','X',
		'.','.','X',
		'X','X','X',
		'.','.','X',
		'X','X','X',
	},
	{//4
		'X','.','X',
		'X','.','X',
		'X','X','X',
		'.','.','X',
		'.','.','X',
	},
	{//5
		'X','X','X',
		'X','.','.',
		'X','X','X',
		'.','.','X',
		'X','X','X',
	},
	{//6
		'X','X','X',
		'X','.','.',
		'X','X','X',
		'X','.','X',
		'X','X','X',
	},
	{//7
		'X','X','X',
		'.','.','X',
		'.','.','X',
		'.','.','X',
		'.','.','X',
	},
	{//8
		'X','X','X',
		'X','.','X',
		'X','X','X',
		'X','.','X',
		'X','X','X',
	},
	{//9
		'X','X','X',
		'X','.','X',
		'X','X','X',
		'.','.','X',
		'X','X','X',
	}
};
int main(){
	int n;
	cin >> n;
	string s;
	cin >> s;
	for(int k = 0;k < 5;k++){
		for(int i = 0;i < s.length();i++){
			int c = s[i]-'0';
			for(int j = 0;j < 3;j++){
				cout << a[c][k][j];
			}
			if(i!=s.length()-1){
				cout << ".";
			}
		}
		cout << endl;
	}
}

 

10.梦中的统计

题目背景

Bessie 处于半梦半醒的状态。过了一会儿,她意识到她在数数,不能入睡。

题目描述

Bessie的大脑反应灵敏,仿佛真实地看到了她数过的一个又一个数。她开始注意每一个数码(0…9):每一个数码在计数的过程中出现过多少次?

给出两个整数 M 和 N (1≤M≤N≤2×10^{9} 以及 N−M≤5×10^{5}),求每一个数码出现了多少次。

输入格式

第 1 行: 两个用空格分开的整数 M 和 N。

输出格式

第 1 行: 十个用空格分开的整数,分别表示数码 0…9 在序列中出现的次数。

输入输出样例

输入 

129 137

输出 

1 10 2 9 1 1 1 1 0 1

代码:

#include<iostream>
using namespace std;
long long M,N;
long long a[10];
int main(){
	cin >> M >> N;
	for(int i = M;i <= N;i++){
		long long x = i;
		while(x){
			a[x%10]++;
			x/=10;
		}
	}
	for(int i = 0;i < 10;i++){
		cout << a[i] << " ";
	}
	return 0;
}

 

 11.珠心算测验

题目描述

珠心算是一种通过在脑中模拟算盘变化来完成快速运算的一种计算技术。珠心算训练,既能够开发智力,又能够为日常生活带来很多便利,因而在很多学校得到普及。

某学校的珠心算老师采用一种快速考察珠心算加法能力的测验方法。他随机生成一个正整数集合,集合中的数各不相同,然后要求学生回答:其中有多少个数,恰好等于集合中另外两个(不同的)数之和?

最近老师出了一些测验题,请你帮忙求出答案。

输入格式

共两行,第一行包含一个整数n,表示测试题中给出的正整数个数。

第二行有n个正整数,每两个正整数之间用一个空格隔开,表示测试题中给出的正整数。

输出格式

一个整数,表示测验题答案。

输入输出样例

输入 

4
1 2 3 4

输出 

2

说明/提示

【样例说明】

由1+2=3,1+3=4,故满足测试要求的答案为2。

注意,加数和被加数必须是集合中的两个不同的数。

【数据说明】

对于100%的数据,3≤n≤100,测验题给出的正整数大小不超过10,000。

分析:

思路:从集合中选取两个不同的数字合成一个数,利用二分查找检查集合中是否有此数,如果有加入set集

易错点:

1.使用binary_search()的前提是数组有序

2.1+4=5和2+3=5算一种,这道题让我们求的是能得到多少个不同的组合数

代码:

#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
const int N = 110;
int a[N];
int n;
int main(){
	cin >> n;
	for(int i = 0;i < n;i++){
		cin >> a[i];
	}
	sort(a,a+n);
	set<int> ans;
	for(int i = 0;i < n;i++){
		for(int j = i+1;j < n;j++){
			int x = a[i]+a[j];
			if(binary_search(a,a+n,x)){
				ans.insert(x);
			}
		}
	}
	cout << ans.size();
	return 0;
}

 

12.爱与愁的心痛

题目描述

最近有 n 个不爽的事,每句话都有一个正整数刺痛值(心理承受力极差)。爱与愁大神想知道连续 m 个刺痛值的和的最小值是多少,但是由于业务繁忙,爱与愁大神只好请你编个程序告诉他。

输入格式

第一行有两个用空格隔开的整数,分别代表 n 和 m。

第 2 到第(n+1) 行,每行一个整数,第(i+1) 行的整数 ai​ 代表第 i 件事的刺痛值 ai​。

输出格式

输出一行一个整数,表示连续 m个刺痛值的和的最小值是多少。

输入输出样例

输入

8 3
1
4
7
3
1
2
4
3

输出 

6

说明/提示

数据规模与约定

  • 对于 30% 的数据,保证 n≤20。
  • 对于 60% 的数据,保证 n≤100。
  • 对于 90% 的数据,保证 n≤10^{3}
  • 对于 100% 的数据,保证 0≤m≤n≤3×10^{3},1≤ai​≤100。

分析:

滑动窗口法(也叫尺取法)

代码:

#include<iostream>
#include<cmath>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 3010;
int n,m;
int a[N];
int main(){
	cin >> n >> m;
	for(int i = 0;i < n;i++){
		cin >> a[i];
	}
	int s = 0,t = 0,cnt = 0,sum = 0,ans = INF;
	for(;;){
		while(t < n && cnt < m){
			sum += a[t++];
			cnt++;
		}
		if(cnt < m){
			break;
		}
		ans = min(ans,sum);
		sum-=a[s++];
		cnt--;
	}
	cout << ans;
	return 0;
	
}

 

13.Bovine Bones G

贝茜喜欢玩棋盘游戏和角色扮演游戏,所以她说服了约翰开车带她去小商店.在那里她买了三个骰子。这三个不同的骰子的面数分别为 s1​,s2​,s3​。

对于一个有 S 个面的骰子每个面上的数字是1,2,3,…,S。每个面(上的数字)出现的概率均等。贝茜希望找出在所有“三个面上的数字的和”中,哪个和的值出现的概率最大。

现在给出每个骰子的面数,需要求出哪个所有“三个面上的数字的和”出现得最频繁。如果有很多个和出现的概率相同,那么只需要输出最小的那个。

数据范围: 2≤s1​≤20,2≤s2​≤20,2≤s3​≤40。

输入格式

* Line 1: Three space-separated integers: S1, S2, and S3

输出格式

* Line 1: The smallest integer sum that appears most frequently when the dice are rolled in every possible combination.

输入输出样例

输入

3 2 3 

输出

5 

说明/提示

Here are all the possible outcomes.

1 1 1 -> 3  
1 2 1 -> 4  
2 1 1 -> 4  
2 2 1 -> 5  
3 1 1 -> 5  
3 2 1 -> 6 
1 1 2 -> 4  
1 2 2 -> 5  
2 1 2 -> 5  
2 2 2 -> 6  
3 1 2 -> 6  
3 2 2 -> 7 
1 1 3 -> 5  
1 2 3 -> 6  
2 1 3 -> 6  
2 2 3 -> 7  
3 1 3 -> 7  
3 2 3 -> 8

Both 5 and 6 appear most frequently (five times each), so 5 is the answer.

代码:

#include<iostream>
using namespace std;
const int N = 110;
int a[N];
int main(){
	int s1,s2,s3;
	cin >> s1 >> s2 >> s3;
	for(int i = 1;i <= s1;i++){
		for(int j = 1;j <= s2;j++){
			for(int k = 1;k <= s3;k++){
				a[i+j+k]++;
			}
		}
	}
	int ans = 0,t = 0;
	for(int i = 0;i < N;i++){
		if(a[i] > t){
			t = a[i];
			ans = i;
		}
	}
	cout << ans;
	return 0;
}

14.开灯

题目描述

在一条无限长的路上,有一排无限长的路灯,编号为1,2,3,4,…。

每一盏灯只有两种可能的状态,开或者关。如果按一下某一盏灯的开关,那么这盏灯的状态将发生改变。如果原来是开,将变成关。如果原来是关,将变成开。

在刚开始的时候,所有的灯都是关的。小明每次可以进行如下的操作:

指定两个数,a,t(a为实数,t为正整数)。将编号为[a],[2×a],[3×a],…,[t×a]的灯的开关各按一次。其中[k]表示实数k的整数部分。

在小明进行了n次操作后,小明突然发现,这个时候只有一盏灯是开的,小明很想知道这盏灯的编号,可是这盏灯离小明太远了,小明看不清编号是多少。

幸好,小明还记得之前的n次操作。于是小明找到了你,你能帮他计算出这盏开着的灯的编号吗?

输入格式

第一行一个正整数n,表示n次操作。

接下来有n行,每行两个数,ai​,ti​。其中ai​是实数,小数点后一定有6位,ti​是正整数。

输出格式

仅一个正整数,那盏开着的灯的编号。

输入输出样例

输入 

3
1.618034 13
2.618034 7
1.000000 21

输出 

20

说明/提示

记T=t1​+t2​+t3​+…+tn​。

对于30%的数据,满足T≤1000

对于80%的数据,满足T≤200000

对于100%的数据,满足T≤2000000

对于100%的数据,满足n≤5000,1≤ai​<1000,1≤ti​≤T

数据保证,在经过n次操作后,有且只有一盏灯是开的,不必判错。而且对于所有的 i 来说,ti​×ai​ 的最大值不超过 2000000。

分析:

这道题最好的解决方法是用异或来解决

先把异或的两个性质复习一下:

        x^x=0

        x^0=x

最后只有一盏灯是开着的,其他灯都是关着的,意思就是对其他灯的操作次数都是成对的,异或完都是0(例:对第3盏灯进行4次操作,打开011,关闭000,打开011,关闭000;其实就是3^3^3^3=0),假设那盏开着的灯是A,也就是A^B^B^C^C^C^C^……=A^0=A;因此我们只需要设ans=0 然后把所有的数异或一遍,即0^(A^B^B^C^C^C^C^……)=A,最后得到A

代码:

#include<iostream>
using namespace std;
int main(){
	int n;
	cin >> n;
	double a;
	int t,ans=0;
	while(n--){
		cin >> a >> t;
		for(int i = 1;i <= t;i++){
			ans ^= int(a*i);
		}
	}
	cout << ans;
	return 0;
}

 

15.蛇形方阵

题目描述

给出一个不大于 9 的正整数 n,输出 n×n 的蛇形方阵。

从左上角填上 1 开始,顺时针方向依次填入数字,如同样例所示。注意每个数字有都会占用 3 个字符,前面使用空格补齐。

输入格式

输出格式

输入输出样例

输入 

4

输出

  1  2  3  4
 12 13 14  5
 11 16 15  6
 10  9  8  7

分析:

设立4个变量分别为上界,下界,左界,右界,就像一个正方形框,每一轮在框上填数,每填完一条边就缩小这条界,一轮下来整个框也就缩小了一圈

代码:

#include<iostream>
#include<stdio.h>
using namespace std;
int main(){
	int n;
	cin >> n;
	int a[n][n] = {0};
	int up = 0,down = n-1,left = 0,right = n-1;
	int num = 1;
	while(num<=n*n){
		for(int i = left;i <= right;i++){
			a[up][i] = num++;
		}
		up++;
		for(int i = up;i <= down;i++){
			a[i][right] = num++;
		}
		right--;
		for(int i = right;i >= left;i--){
			a[down][i] = num++;
		}
		down--;
		for(int i = down;i >= up;i--){
			a[i][left] = num++;
		}
		left++;
	}	
	for(int i = 0;i < n;i++){
		for(int j = 0;j < n;j++){
			printf("%3d",a[i][j]);
		}
		cout << endl;
	}
	return 0;
} 

 

16.杨辉三角

题目描述

给出 n(n≤20),输出杨辉三角的前 n 行。

如果你不知道什么是杨辉三角,可以观察样例找找规律。

输入格式

输出格式

输入输出样例

输入

6

输出

1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1

代码:

#include<iostream>
using namespace std;
int main(){
	int n;
	cin >> n;
	int a[n][n] = {0};
	a[0][0] = 1;
	for(int i = 1;i < n;i++){
		a[i][0] = 1;
		for(int j = 1;j < i;j++){
			a[i][j] = a[i-1][j-1]+a[i-1][j];
		}
		a[i][i] = 1;
	}
	for(int i = 0;i < n;i++){
		for(int j = 0;j <= i;j++){
			cout << a[i][j] << " ";
		}
		cout << endl;
	}
	return 0;
} 

 

17.插火把

题目描述

话说有一天 linyorson 在“我的世界”开了一个n×n(n≤100)的方阵,现在他有 m 个火把和 k个萤石,分别放在(x1​,y1​)∼(xm​,ym​) 和 (o1​,p1​)∼(ok​,pk​) 的位置,没有光或没放东西的地方会生成怪物。请问在这个方阵中有几个点会生成怪物?

P.S. 火把的照亮范围是:

    |暗|暗| 光 |暗|暗|
    |暗|光| 光 |光|暗|
    |光|光|火把|光|光|
    |暗|光| 光 |光|暗|
    |暗|暗| 光 |暗|暗|

萤石:

    |光|光| 光 |光|光|
    |光|光| 光 |光|光|
    |光|光|萤石|光|光|
    |光|光| 光 |光|光|
    |光|光| 光 |光|光|

输入格式

输入共 m+k+1 行。
第一行为 n,m,k。
第 2 到第 m + 1 行分别是火把的位置 xi​,yi​。
第 m+2 到第 m+k+1 行分别是萤石的位置 oi​,pi​。

注:可能没有萤石,但一定有火把。

所有数据保证在 int 范围内。

输出格式

有几个点会生出怪物。

输入输出样例

输入 

5 1 0
3 3

输出 

12

分析:

1.这里为了避免重复计算,我们把火把和萤石放到一起输入;只不过如果是火把照亮的范围会缩小一点,那到底固定在什么范围内呢?

偏移量(x,y)如下:

 落在这个菱形区域内的所有点都满足:|x|+|y| <= 2

2.把所有发光的点放入set集合(自动去重),最后用所有的点数-发光的点数就是不发光的点数

注意如果火把的位置是(3,3),那么代表的是第三行第三列;所以方阵的范围应该是[1,1]~[n,n]

代码:

#include<iostream>
#include<cmath>
#include<set>
using namespace std;
set<pair<int,int> > s;
int main(){
	int n,m,k;
	cin >> n >> m >> k;
	int x,y;
	for(int i = 0;i < m+k;i++){
		cin >> x >> y;
		for(int j = -2;j <= 2;j++){
			for(int g = -2;g <= 2;g++){
				//如果是火把,那么注意j,g的某些取值要舍弃 
				if((i >= m || abs(j)+abs(g)<=2) && (x+j>=1&&x+j<=n&&y+g>=1&&y+g<=n)){
					s.insert(make_pair(x+j,y+g));
				}
			}
		}
	}
	cout << n*n-s.size();
	return 0;
} 

 

18.压缩技术

题目描述

设某汉字由N × N的0和1的点阵图案组成。

我们依照以下规则生成压缩码。连续一组数值:从汉字点阵图案的第一行第一个符号开始计算,按书写顺序从左到右,由上至下。第一个数表示连续有几个0,第二个数表示接下来连续有几个1,第三个数再接下来连续有几个0,第四个数接着连续几个1,以此类推……

例如: 以下汉字点阵图案:

0001000
0001000
0001111
0001000
0001000
0001000
1111111

对应的压缩码是: 7 3 1 6 1 6 4 3 1 6 1 6 1 3 7 (第一个数是N ,其余各位表示交替表示0和1 的个数,压缩码保证 N × N=交替的各位数之和)

输入格式

一行,压缩码。

输出格式

汉字点阵图(点阵符号之间不留空格)。(3<=N<=200)

输入输出样例

输入 

7 3 1 6 1 6 4 3 1 6 1 6 1 3 7

输出

0001000
0001000
0001111
0001000
0001000
0001000
1111111

代码: 

#include<iostream>
using namespace std;
int main(){
	int N;
	cin >> N;
	int k,idx = 1,flag = 0; 
	while(cin >> k){
		for(int j = 0;j < k;j++,idx++){
			cout << flag;
			if(idx%N==0){//如果该行已经输出了N个数就需换行 
				cout << endl;
			}
		}
		flag = 1-flag;//实现0和1之间的转换 
	} 
	return 0;
} 

 

19.压缩技术(续集版)

题目描述

设某汉字由N × N的0和1的点阵图案组成。

我们依照以下规则生成压缩码。连续一组数值:从汉字点阵图案的第一行第一个符号开始计算,按书写顺序从左到右,由上至下。第一个数表示连续有几个0,第二个数表示接下来连续有几个1,第三个数再接下来连续有几个0,第四个数接着连续几个1,以此类推……

例如: 以下汉字点阵图案:

0001000
0001000
0001111
0001000
0001000
0001000
1111111

对应的压缩码是: 7 3 1 6 1 6 4 3 1 6 1 6 1 3 7 (第一个数是N ,其余各位表示交替表示0和1 的个数,压缩码保证 N×N = 交替的各位数之和)

输入格式

汉字点阵图(点阵符号之间不留空格)。(3<=N<=200)

输出格式

一行,压缩码。

输入输出样例

输入

0001000
0001000
0001111
0001000
0001000
0001000
1111111

输出

7 3 1 6 1 6 4 3 1 6 1 6 1 3 7

分析:

 这里解决了本博主的一个疑惑:为什么while(cin>>c)会自动终止呢?

答:只有luogu这样的在线IDE(在应用里面)他才会自动结束输入,但是我们自己测试的时候需要加ctrl+z来终止(为什么需要用ctrl+z来终止呢?因为cin会忽略空格或者enter,只有遇到文件结束符ctrl+z才会结束循环)。

小知识:当自己在终端调试的时候输入数字并多次回车始终无法结束while循环,到底是为什么?

原因:
cin是istream类型的对象,这个对象也被称为标准输入。
>>为输入运算符
左侧参数:istream对象
右侧参数:任意对象
返回值:返回istream对象
作用:它从给定的istream读入数据,并存入给定的对象中
分析std::cin >> value
此表达式从标准输入读取下一个数,保存在value中,输入运算符返回其左侧运算对象,在这个示例中是std::cin.因此,此循环实际上检测的是std::cin。
当我们使用一个istream对象作为条件时,其效果是检测流的状态。如果流是有效的,即流未遇到错误,那么检测成功。当遇到文件结束符,或遇到一个无效输入时,istream对象的状态会变成无效。处于无效的istream对象为使条件为假。因此,while循环一直会执行,直到遇到文件结束符或者错误。
小提示:windows下的输入文件结束符为Ctrl+Z,Unix和Linux下一般是Ctrl+D

代码:

#include<iostream>
#include<cmath>
using namespace std;
const int N = 210;
int ans[N*N];
int main(){
	char c,flag = '0';
	int idx = 0,cnt = 0;
	while(cin >> c){
		cnt++;
		if(c != flag){
			ans[++idx]++;
			flag = c;
		}else{
			ans[idx]++;
		}
	}
	cout << sqrt(cnt);
	for(int i = 0;i <= idx;i++){
		cout << " " << ans[i];
	}
	return 0;
} 

 

20.方块转换

题目描述

一块n×n 正方形的黑白瓦片的图案要被转换成新的正方形图案。写一个程序来找出将原始图案按照以下列转换方法转换成新图案的最小方式:

  • 转 90°:图案按顺时针转 90°。

  • 转 180°:图案按顺时针转 180°。

  • 转 270°:图案按顺时针转 270°。

  • 反射:图案在水平方向翻转(以中央铅垂线为中心形成原图案的镜像)。

  • 组合:图案在水平方向翻转,然后再按照 1∼3 之间的一种再次转换。

  • 不改变:原图案不改变。

  • 无效转换:无法用以上方法得到新图案。

如果有多种可用的转换方法,请选择序号最小的那个。

只使用上述 7 个中的一个步骤来完成这次转换。

输入格式

第一行一个正整数 n。

然后 n 行,每行 n 个字符,全部为 @ 或 -,表示初始的正方形。

接下来 n 行,每行 n 个字符,全部为 @ 或 -,表示最终的正方形。

输出格式

单独的一行包括1∼7 之间的一个数字(在上文已描述)表明需要将转换前的正方形变为转换后的正方形的转换方法。

输入输出样例

输入 

3
@-@
---
@@-
@-@
@--
--@

输出

1

说明/提示

【数据范围】
对于100% 的数据,1≤n≤10。

分析:

这道题主要是两个步骤。一个是旋转90度,一个是反射(绕y轴翻转180度)。

a为变化后的数组,b为原数组,旋转90度后:a[i][j] = b[n-1-j][i];反射后:a[i][j] = b[i][n-1-j]

因为它是一步一步验证的,所以进行操作2时,一定已经进行完了操作1,所以只需再旋转90度即可,操作3在操作2的基础上再旋转90度;操作4需要重新对a进行操作(因为和前3个操作不联系),操作5在操作4的基础上再次顺序进行操作1,2,3即可

代码:

#include<iostream>
#include<cstring>
using namespace std;
const int N = 15;
int n;
//由于C++返回一个二位数组极其麻烦,所以我们将它放到一个结构体中 
struct Matrix{
	char a[N][N];
	bool operator==(Matrix t){//判断两个矩阵是否相等 
		for(int i = 0;i < n;i++)
			for(int j = 0;j < n;j++)
				if(a[i][j] != t.a[i][j])
					return false;
		return true;
	}
}a,b,t;
Matrix rotate(Matrix t){//绕中心旋转90度,返回翻转后的矩阵 
	Matrix c;
	for(int i = 0;i < n;i++)
		for(int j = 0;j < n;j++)
			c.a[i][j] = t.a[n-1-j][i];
	return c; 
}
Matrix reflect(Matrix t){//绕y轴翻转180度  
	Matrix c;
	for(int i = 0;i < n;i++)
		for(int j = 0;j < n;j++)
			c.a[i][j] = t.a[i][n-1-j];
	return c;	
}
int main(){
	cin >> n;
	for(int i = 0;i < 2*n;i++){
		if(i<n) cin >> a.a[i];
		else cin >> b.a[i-n];
	}
	//赋给一个临时变量 
	t = a;
	for(int i = 1;i <= 6;i++){
		if(i <= 3){
			t = rotate(t);
			if(t == b){
				cout << i;
				return 0;
			}
		}else if(i == 4){
			t = a;
			t = reflect(t);
			if(t == b){
				cout << 4;
				return 0;
			}
		}else if(i == 5){
			for(int j = 1;j <= 3;j++){
				t = rotate(t);
				if(t == b){
					cout << 5;
					return 0;
				}
			}
		}else{
			if(a == b){
				cout << 6;
				return 0;
			}
		}
	}
	cout << 7; 
	return 0;
} 

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值