第十四届蓝桥杯省赛Java A组/C组——平均(贪心算法)

题目来源:5395. 平均 - AcWing题库

题目 3179: 蓝桥杯2023年第十四届省赛真题-平均 - C语言网 (dotcpp.com)

蓝桥杯2023年第十四届省赛真题-平均

时间限制: 5s 内存限制: 576MB 提交: 2879 解决: 711

题目描述

有一个长度为 n 的数组(n 是 10 的倍数),每个数 ai 都是区间 [0, 9] 中的整数。小明发现数组里每种数出现的次数不太平均,而更改第 i 个数的代价为bi,他想更改若干个数的值使得这 10 种数出现的次数相等(都等于n/10),请问代价和最少为多少。

输入格式

输入的第一行包含一个正整数 n 。

接下来 n 行,第 i 行包含两个整数 ai , bi ,用一个空格分隔。

输出格式

输出一行包含一个正整数表示答案。

样例输入

复制

10
1 1
1 2
1 3
2 4
2 5
2 6
3 7
3 8
3 9
4 10

样例输出

复制

27

提示

只更改第 1, 2, 4, 5, 7, 8 个数,需要花费代价 1 + 2 + 4 + 5 + 7 + 8 = 27 。

对于 20% 的评测用例,n ≤ 1000;

对于所有评测用例,n ≤ 100000, 0 < bi ≤ 2 × 105 。

初始代码:

#include<iostream>
#include<algorithm>
#include<map>

using namespace std;

const int N=100010;
int n;
pair<int,int>ab[N];//<ai,bi>
map<int,int>mp;//统计各种元素出现次数
int sum;

int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>ab[i].first>>ab[i].second;
		mp[ab[i].first]++;
	}
	
	sort(ab,ab+n);// pair默认对first升序,当first相同时对second升序
	for(int i=0;i<n;i++){
		if(mp[ab[i].first]!=1){//ai有重复,次数大于1
			sum+=ab[i].second;//更改,加上代价bi
			mp[ab[i].first]--;//对应数字ai次数减1
		}
	}
	
	cout<<sum;
	 return 0;
}

结果大好多: 

代码提交状态: Wrong Answer   
代码运行状态: 错误数据如下所示
输入
1000
4 923
4 633
6 4
9 47
9 962
4 500
9 933
4 253
6 324
6 659
9 391
6 283
3 269
8 464
4 242
4 350
5 648
4 699
4 956
4 603
1 6
1 684
4 809
4 1000
3 476
9 681
6 765
1 254
4 723
6 766
4 990
5 243
9 323
9 556
4 968
4 661
9 607
9 611
8 521
6 20
4 128
4 552
4 443
6 728
6 987
3 538
4 12
3 472
9 845
4 198
3 933
6 109
9 448
6 533
1 734
4 256
8 604
9 785
9 402
1 371
6 807
6 941
6 673
7 44
5 385
7 85
9 98
4 765
5 704
2 522
4 920
3 497
7 839
4 338
4 842
4 275
4 728
7 231
4 332
8 679
1 635
4 770
8 202
1 3
6 815
4 426
0 88
9 42
2 317
4 474
3 259
5 340
2 629
4 901
1 37
7 434
4 444
5 117
5 188
1 463
4 284
6 870
4 564
4 767
6 166
4 320
4 541
1 383
7 601
9 127
9 648
9 336
6 25
3 616
9 551
4 898
6 616
4 120
9 101
9 782
6 492
5 832
7 700
4 584
9 854
9 240
6 150
4 46
4 283
3 141
6 550
6 468
4 928
9 413
9 599
9 595
5 227
4 205
4 497
1 573
4 487
4 774
5 883
4 168
3 916
6 736
5 590
6 847
4 227
9 922
3 791
9 219
9 901
6 386
4 788
6 406
6 16
9 346
3 876
7 472
4 636
6 260
4 240
1 950
4 961
1 972
6 731
7 991
4 75
9 495
4 889
6 760
4 900
9 565
8 196
7 589
6 485
9 105
6 250
4 418
4 548
3 958
4 809
6 309
4 993
4 682
4 570
7 848
5 426
1 610
1 15
2 864
4 973
1 1
4 845
4 141
8 313
7 676
7 516
9 386
4 251
6 766
6 992
4 138
4 585
9 840
6 769
6 414
4 121
4 453
5 15
9 122
6 717
4 454
6 430
4 136
9 19
3 163
5 863
9 213
5 348
6 208
6 882
4 517
3 531
4 520
6 996
1 340
1 518
2 498
6 459
9 324
4 381
6 925
6 514
1 395
3 334
1 159
9 685
8 364
6 446
3 874
6 157
9 276
1 486
6 332
9 990
6 415
1 945
3 948
3 566
6 918
6 168
2 420
9 804
5 6
8 106
1 468
4 85
5 785
6 205
2 424
9 951
5 431
4 663
9 704
4 503
4 992
4 62
1 179
3 765
4 680
9 76
7 797
9 480
4 429
4 69
4 696
4 169
6 176
9 784
3 61
6 259
7 92
3 998
9 744
9 826
4 298
9 873
6 339
9 702
4 745
4 32
9 974
1 50
1 517
6 316
9 470
7 816
9 94
6 847
9 40
5 228
9 701
4 368
7 839
8 978
4 312
9 662
6 178
9 983
5 197
6 430
3 371
9 727
4 372
1 677
4 137
3 47
6 833
9 412
4 158
6 476
4 998
8 716
4 466
9 64
7 211
1 188
9 301
4 643
4 168
8 433
4 545
4 58
1 923
6 269
4 437
9 ...
输出
497289
标准答案
125849

调试后,以下error小问题,对结果无影响;问题出在判断条件上mp[ab[i].first] != 1 ,导致结果比实际大好多:

//const int N=100010;
//pair<int,int>ab[N];//<ai,bi>
ab = <error reading variable: value requires 800080 bytes, which is more than max-value-size>

改vector<pair<int,int>>ab(n)动态数组,error消除;改用局部变量,调试可看到ab具体值;以及发现自己忽略了题目条件n/10,而且是只对次数大于n/10的做操作。

上一个测试数据过了,但下一个似乎数据溢出了:

#include<iostream>
#include<algorithm>
#include<map>

using namespace std;

const int N=100010;
//int n;
//pair<int,int>ab[N];//<ai,bi>
//map<int,int>mp;//统计各种元素出现次数
//int sum;

int main(){
	int n;
	cin>>n;
	vector<pair<int,int>>ab(n);//<ai,bi>
	map<int,int>mp;//统计各种元素出现次数
	int sum;
	for(int i=0;i<n;i++){
		cin>>ab[i].first>>ab[i].second;
		mp[ab[i].first]++;
	}
	
	sort(ab.begin(),ab.end());// pair默认对first升序,当first相同时对second升序
	for(int i=0;i<n;i++){
		if(mp[ab[i].first]>n/10){//ai有重复,次数大于1//没看题,是n/10不是1!
			sum+=ab[i].second;//更改,加上代价bi
			mp[ab[i].first]--;//对应数字ai次数减1//次数多的减,少的对应就加,不用操作
		}
	}
	
	cout<<sum;
	 return 0;
}
/*
  10
  2 2
  1 6
  1 2
  1 5
  3 4
  3 6
  4 0
  4 5
  4 1
  9 0
 */
代码提交状态: Wrong Answer   
代码运行状态: 错误数据如下所示   ×
输入
100000
5 135217
8 51886
6 14363
0 79816
6 142829
0 183303
1 127824
7 70164
5 155423
7 130114
8 127862
5 63515
5 26202
8 188513
1 93358
5 104291
8 157559
8 57753
1 139604
9 94671
6 121654
4 60110
1 196632
6 3338
6 166519
0 146893
1 69560
6 182656
1 170003
0 24969
1 69652
4 23025
6 100972
6 164173
1 101270
8 96950
8 180063
5 64470
8 9016
1 164364
5 37670
1 128
1 42621
5 49279
1 92657
1 64911
0 162996
5 85223
6 104407
8 69707
5 37684
6 150406
1 181262
9 82187
5 198308
6 180957
0 39490
8 132650
6 70985
6 52977
2 109638
4 198187
6 116757
8 61526
6 162176
8 192849
6 84331
1 97200
1 149833
1 143162
6 53592
6 136279
9 118541
1 195970
5 85215
0 57169
1 86849
6 68008
6 56591
1 101760
1 37934
6 190211
8 54723
1 15246
1 150517
8 19780
7 92194
9 17099
1 174446
6 40449
5 79224
6 132725
1 143406
1 162835
9 181875
8 12427
3 111310
6 78116
8 173875
4 16657
1 183889
8 105899
0 120099
8 91003
4 87302
6 48156
1 104233
6 99195
7 123198
6 112538
9 98881
9 179294
1 130247
5 5370
1 79000
8 165734
1 173665
3 146464
6 133800
2 18056
8 146204
8 113264
5 165125
6 75282
7 135026
8 124703
6 37606
6 25494
9 61152
6 162737
1 21495
8 178926
6 115091
1 190575
1 60423
6 10601
8 42687
7 178859
8 91377
4 150427
7 129896
6 172117
1 45809
8 36190
6 989
8 63270
6 79248
1 78243
7 73669
1 151595
0 568
8 143188
1 181260
1 153427
8 22641
1 55000
6 159920
1 63114
0 198248
5 69108
6 176091
6 24039
6 198949
9 41311
4 87550
5 156945
8 79047
4 59380
6 159585
7 113908
1 127630
0 113460
8 45330
1 15422
1 169643
6 58980
5 168693
6 115716
1 20597
6 60368
6 85117
3 28921
9 32998
9 22071
8 83613
8 132614
2 88073
0 108501
6 56612
6 49964
9 2933
9 169514
5 159748
0 98783
1 90605
1 138294
1 33906
2 1868
9 55390
5 62175
8 32332
1 28887
6 125337
5 88338
3 153261
8 102414
1 2358
1 186572
8 109893
1 57096
6 153836
9 68899
1 99234
5 69717
9 188947
4 199700
2 25194
6 187235
7 183467
6 169866
6 63910
7 42022
5 174965
8 14453
0 63138
6 176367
9 98272
6 163712
1 151342
1 82209
1 149550
6 138480
5 79154
5 68137
6 146824
1 164427
...
输出
-2106722123
标准答案
2188245173

用来保存和的数据爆了:

int

4 个字节

-2,147,483,648 到 2,147,483,6472*10^9(一定能保证9位数)

unsigned int

4 个字节

0 到 4,294,967,295(4*10^9

long long

8 个字节

双长~ -9,223,372,036,854,775,807 到 9,223,372,036,854,775,807 的范围

(9*10^18)(一定能保证18位数)

最大数据到:2*10^10,超int范围,故用long long。以后求和题都要考虑最大取值范围,但用long long 一定够

AC代码:

#include<iostream>
#include<algorithm>
#include<map>

using namespace std;

const int N=100010;
//int n;
//pair<int,int>ab[N];//<ai,bi>
//map<int,int>mp;//统计各种元素出现次数
//int sum;

int main(){
	int n;
	cin>>n;
	vector<pair<int,int>>ab(n);//<ai,bi>
	map<int,int>mp;//统计各种元素出现次数
	long long int sum=0;
	for(int i=0;i<n;i++){
		cin>>ab[i].first>>ab[i].second;
		mp[ab[i].first]++;
	}
	
	sort(ab.begin(),ab.end());// pair默认对first升序,当first相同时对second升序
	for(int i=0;i<n;i++){
		if(mp[ab[i].first]>n/10){//ai有重复,次数大于1//没看题,是n/10不是1!
			sum+=ab[i].second;//更改,加上代价bi
			mp[ab[i].first]--;//对应数字ai次数减1//次数多的减,少的对应就加,不用操作
		}
	}
	
	cout<<sum;
	 return 0;
}

然而最后才发现 sum 局部变量没有初始化!虽然最后改了long long后ac了,看正确结果确实要long long,但是原来数据错误的原因还有sum初始值为随机值!因为编译器调试只能看到局部变量,所以后面将全局变量直接复制到main函数中,所以忽略了初始化,以后全局变量也必须给定一个初始值!全局变量不初始化是一个很不好的习惯!

AC代码(不用vector)

#include<iostream>
#include<algorithm>
#include<map>

using namespace std;

const int N=100010;
int n;
pair<int,int>ab[N];//<ai,bi>
map<int,int>mp;//统计各种元素出现次数
long long int sum=0;

int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>ab[i].first>>ab[i].second;
		mp[ab[i].first]++;
	}
	
	sort(ab,ab+n);// pair默认对first升序,当first相同时对second升序
	for(int i=0;i<n;i++){
		if(mp[ab[i].first]>n/10){//ai有重复,次数大于1//ai重复次数大于n/10
			sum+=ab[i].second;//更改,加上代价bi
			mp[ab[i].first]--;//对应数字ai次数减1
		}
	}
	
	cout<<sum;
	return 0;
}

故!本题bug关键:

  1. 判断条件:if(mp[ab[i].first]>n/10){//ai重复次数大于n/10
  2. 局部变量的初始化

而贪心思想还是体现在对二元组的排序上,只加小数,使得总数最小,非常简单的思想,关键在于如何运用数据结构合理实现

回看上一题,其贪心思想也是体现在排序上,每一步都是为了总体最优第十四届蓝桥杯省赛C++ C组——三国游戏(贪心算法)-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_74741271/article/details/137090431

y总思想讲解及算法

#include<iostream>
#include<algorithm>
#include<map>
#include<vector>

using namespace std;
typedef long long LL;
int n;
vector<int> w[10];//10个数的不同代价,数字作为横坐标,代价个数作为纵坐标
//10个容器并排放,分别装自己的代价

int main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		int a,b;
		scanf("%d%d",&a,&b);
		w[a].push_back(b);//将代价存入对应数字的容器vector
	}
	LL res=0;//计算代价
	int avg=n/10;
	for(int i=0;i<10;i++){//对每一个数字的容量判断
		if(w[i].size()>avg){
			sort(w[i].begin(),w[i].end());
			for(int j=0;j<w[i].size()-avg;j++)//多出平均值的分摊出去,分(个数-avg)个
				res+=w[i][j];//小的代价先计入
		}
	}
	printf("%lld",res);
	return 0;
}

统计图模型:数据归类、数据分析、数据操作,详情见oneNote笔记本 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值