如何实现对数列取余后对不同类数据进行计数(包括sort和unique函数第三参数的用法)——以P4325 [COCI2006-2007#1] Modulo为例

目录

引言

题目描述 

分析 

方法一(骗)

批判 

方法二

C++代码

方法三

C++代码

方法四


引言

我们先来看总的问题——如何实现对数列取余后对不同类数据进行计数,对于计数大家都是非常熟悉的,只要a不等于b就代表着两数不同,但是当我们对所给的数据进行取余后,原来不同的两数则成为同一类数据,只进行一次计数(eg:若对4取余,2与6则为同一个数字)。故此我今天以洛谷排序题库里面的P4325 [COCI2006-2007#1] Modulo 为例题来给大家解决一下这个问题 。

 [COCI2006-2007#1] Moduloicon-default.png?t=N2N8https://www.luogu.com.cn/problem/P4325

题目描述 

分析 

这道题会输给我们10个数字,然后在这10个数分别取余之后对其逐个计数(%42之后余数不同则记为不同),最后将记得数输出即可。

接下来我们看一下我对这个题目的见解和所能想到的3种方法👇

方法一(骗)

由于这道题目只会输入固定个数的数据,并且这个固定的个数才10,那么对于这种数据量很小的题目,我们直接暴力求解就可以——类似于冒泡排序一样利用循环嵌套的结构对数组进行多次的遍历,然后判断其是否相同就可以,相同计数器+1并将后面的数字改变(同样要保证变的数不会产生新的计数详情可见之前的博客如何实现对数组的去重方法一),不同则继续向后遍历就可以了

代码如下👇

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int a[10];                //开对应大小的数组存放数列
	int i,j,num=0;            //初始化计数器
	for(i=0;i<10;i++){
		cin >> a[i] ;
		a[i]%=42;            //存放时就将其取余
	}
	for(i=0;i<10;i++){
		if(a[i]!=-1)
		num++;            //见了新的数就能让计数器+1
		for(j=i+1;j<10;j++){
			if(a[i]!=-1&&a[j]!=-1){        //如果都未执行过判断就能继续进行
				if(a[i]!=a[j]){
					num++;            //不同计数器+1
					a[j]=-1;            //将判断过的数字标记
			}
			}
		}
	}
	cout << num ;
	return 0;
}

批判 

这样是正确的吗?这段代码能AC吗?不能!!!

那为什么这个思路不对,为什么这段代码不能实现题目的要求?

主要的问题在于没有考虑如果第二位与第三位数字一样或者余数一样的情况,举个例子,如果这十个数是一个1和九个2,那么完成第一轮判断的时候我们的计数器就已经出了大问题了——很明显这里只有两个不同的数字,但是由于我们是在拿着1一直进行判断,后面的九个2每个都被记了一次,再加上一开始的1,此时的num已经成了10了,这是一个不写不知道,一写嘎嘎易错的点,希望大家应以为戒!!!

故此这个办法是行不通的,或者并不是解决这个问题的最优解,我们来看看其他的两种方法

  相信博主,博主不会再骗你们了嘤嘤嘤  

方法二

既然逐个的比较我们行不通,但是我们却是可以进行计数,通过类似于计数排序的思维给他们设置自己的票箱,有这个对应的余数就将这个票箱里面的数+1,最后遍历所有票箱进行唱票就可以了。

明白了整体的思路这时候就可以祭出我的AC代码了

C++代码

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int a[10];
	int b[42]={0};        //设置每个余数对应的票箱
	int i,num=0;
	for(i=0;i<10;i++){
		cin >> a[i] ;
		a[i]%=42;        //存入时进行取余操作
		b[a[i]]++;        //将票存入对应的票箱
	}
	for(i=0;i<42;i++){
		if(b[i]!=0){
			num++;        //有票就让num++
		}
	}
	cout << num ;
	return 0;
}

这个题目这样我们就解决了,用类似于存票唱票的形式统计出有多少种这样的不同类别的数字。

方法三

接下来的这个方法才贴合这个题目有的标签——排序,用到了sort快排以及unique去重函数,这两个函数之前都给大家讲过了,大家是否还记得这两个函数的三个变量是完全相同的,分别是数组首地址;数组末地址的下一位;标准;这个所谓的标准分别是判断大小的标准和判断相同的标准。不写特别书写标准的话默认从小到大排列,默认a=b为相等。

那么这道题目相等的标准变了,变成了两个数对42取余后相同则为相同,那我们只要书写出对应的标准函数就可以了。

当然了,大家在看过如何实现对数组的去重这篇文章之后也都知道要实现去重先要做的是排序使得相同元素相邻,故此我们还需要改写sort函数的排序标准cmp。

bool cmp(int a,int b){
	return (a%42)>(b%42);        //sort函数的排序准则
}
bool equ(int a,int b){
	return (a%42)==(b%42);        //unique判断相等的准则
}

大家会发现这两个作为准则的函数依旧是非常相似,都是如果要按照(a%42)>(b%42)的标准,就将他放在return 后边表示这个排序准则或者判断相等的标准是true的

C++代码

#include <bits/stdc++.h>
using namespace std;
bool cmp(int a,int b){
	return (a%42)>(b%42);
}
bool equ(int a,int b){
	return (a%42)==(b%42);
}
int main()
{
	int a[10];
	int i,num=0;
	for(i=0;i<10;i++){
		cin >> a[i] ;
	}
	sort(a,a+10,cmp);            //进行sort排序
	num=unique(a,a+10,equ)-a;        //按照既定的标准去重并取得去重后的数组长度
	cout << num ;
	return 0;
}

嘿嘿,很明显大家发现复杂了嘛 主要是想让大家学习如何自定义sort函数和unique函数的第三个变量  

其实要用sort+unique函数还是很简单的,直接在存储的时候就%42不就好了吗,何必要改变这两个的排序准则和判断相等的标准呢

方法四

#include <bits/stdc++.h>        //万能头文件
using namespace std;
int main()
{
	int a[10];
	int i,num=0;
	for(i=0;i<10;i++){
		cin >> a[i] ;
		a[i]%=42;            //存入时就对42取余
	}
	sort(a,a+10);            //直接进行sort排序
	num=unique(a,a+10)-a;        //直接比较余数就可以,不需要定义新的判断准则
	cout << num ;
	return 0;
}

好了,这就是博主为大家整理出来的几种方法,有大家容易犯错误入其中的错误方法一,也有存票唱票的方法二,有想让大家通过其学习到sort和unique函数第三参数用法的方法三,当然也有简化后的方法四,希望对大家有所帮助,谢谢大家的阅读~~~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值