目录
前言
做题时,统计一个数字的出现次数是常见的情况,但是有些时候会出现下面这种情况
翻译软件不太行
题意:
就是有N份面条,每份面条有一个长度Ai
现在有个人它接下来M的天,每天要吃长度为Bi的面条,询问一下是否能够满足他的要求。
显然,这题我们只需要统计一下每个长度面条的出现次数,然后再判断一下即可。
不难写出以下代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3+10,M = N * 2;
int cnt[N];
int main()
{
ios::sync_with_stdio(false);
int n,m;
cin>>n>>m;
for(int i = 1 ; i <= n ; i++)
{
int x;
cin>>x;
cnt[x]++;//统计出现次数
}
for(int i = 1 ; i <= m ; i++)
{
int x;
cin>>x;
if(cnt[x]==0)//没面条了,直接结束
{
cout<<"No"<<'\n';
return 0;
}
cnt[x]--;//面条被吃掉了,需要减去
}
cout<<"Yes"<<'\n';
return 0;
}
当然,这样是不可以的,我们再来看看这题的空间限制这么大的吗
1M的空间大约可以开25万大小的数组,粗略一算2500万,而这题想要统计出所有的数,必须要保证开10亿大小的数组,两者之间相差甚远。
所以就要请出今天的主角:离散化
离散化
1.可能要用的前置知识
- stl中的vector,unique,sort(应该都会的吧
- 没了吧(大概
不会也没事,大概往下看一遍就会了应该吧
2.map实现离散化(stl香香香
如果还有不会map的读者呢可以自行去阅读其他的map博客
还是由我来简单介绍一下吧有没有一种可能是博主觉得读者自己去读别的博客太辛苦了
(不想看的可以跳过)
1.建立map
map<int,int> mp;
2.使用map(比如上面的统计看起来根本没变化好吗
for(int i = 1; i <= n ; i++)
{
int x;
cin>>x;
mp[x]++;
}
map给两个数(int与int)之间建立起了映射关系,不妨可以理解为f(x) = y。
为了更清晰得与数组之间区分,看看下面这个例子
map<double,int> mp;
mp[1.5] = 1;
是吧,应该可以理解map的用法了吧,内部原理不是这里的重点绝对不是因为懒(大声)
所以就有了一下代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+10,M = N * 2;
int main()
{
ios::sync_with_stdio(false);
map<int,int> mp;
int n,m;
cin>>n>>m;
for(int i = 1; i <= n ;i++)
{
int x;
cin>>x;
mp[x]++;
}
for(int i = 1 ; i <= m ; i++)
{
int x;
cin>>x;
if(mp[x]==0)
{
cout<<"No"<<'\n';
return 0;
}
mp[x]--;
}
cout<<"Yes"<<'\n';
return 0;
}
代码很简单就不多赘述了
这里要提一嘴的是,map内部是红黑树实现,所以访问一个数所需的时间是O(logn)
unorder_map震怒:为什么不用我,我可是O(1)
我:hh,你忘了你被hack时O(n)的可笑场景了吗,源代码公开时用你不是纯纯找死
3.正常版本(可能
所谓离散化,就是建立映射关系,放图!!!
你画图时的拉跨样子属实可笑
我们这样就把[0,1000]范围内的数映射成了范围[0,10]内的数
其实这里用到的映射方法就是——数组下标
比如这题,我们可以发现,虽数的范围很大[1,1e9],但是数的个数是很少的,加起来的总数不会超过2000,所以这个时候就可以用正常的统计方法了。
所以离散化的步骤就很显然了:
1.先存下本题中所需要用到的所有数
2.为了方便的找到原来数所在的位置(映射),我们要对所有数排序
3.我们可以从函数角度理解,一个x只能对应一个y,所以要对排序后的数进行去重处理
那么就开始吧:
1.开一些数组
vector<int> all;//用于离散化
int cnt[N],query[N],a[N];//cnt统计,query存下所有询问,a数组存下所有面条
2.存下所有的数
for(int i = 1 ; i <= n ; i++)cin>>a[i],all.push_back(a[i]);
for(int i = 1 ; i <= m ; i++)cin>>query[i],all.push_back(query[i]);
3.排序,去重
这里直接使用的是stl的内置函数(不嫌烦也可以手写
#include<bits/stdc++.h>//不加上这一行好像下面代码没有颜色(笑死
sort(all.begin(),all.end());
all.erase(unique(all.begin(),all.end()),all.end());
这两行还是蛮固定的吧,基本上都是这么操作的。
4.最后,怎么找到一个数映射以后的值
由于数是有序的,我们可以使用二分去处理
int find(int x)
{
return lower_bound(all.begin(),all.end(),x)-all.begin();
}
大概就这么一行吧(手写,都可以手写
然后一份热乎乎的AC代码就出炉了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3+10,M = N * 2;
vector<int> all;
int cnt[N],query[N],a[N];
int find(int x)
{
return lower_bound(all.begin(),all.end(),x)-all.begin();
}
int main()
{
ios::sync_with_stdio(false);
int n,m;
cin>>n;cin>>m;
for(int i = 1 ; i <= n ; i++)cin>>a[i],all.push_back(a[i]);
for(int i = 1 ; i <= m ; i++)cin>>query[i],all.push_back(query[i]);
sort(all.begin(),all.end());
all.erase(unique(all.begin(),all.end()),all.end());
for(int i = 1 ; i <= n ; i++)
{
int x = find(a[i]);//找到映射以后的数
cnt[x]++;
}
for(int i = 1 ; i <= m ; i++)
{
int x = find(query[i]);//找到映射以后的数
if(cnt[x]==0)
{
cout<<"No"<<'\n';
return 0;
}
cnt[x]--;
}
cout<<"Yes"<<'\n';
return 0;
}
B - Pasta (atcoder.jp)https://atcoder.jp/contests/abc241/tasks/abc241_b题目摆这了,大家可以试试
题外话
2月26日,我们的爱酱无限期休眠了...emmmm......
emmmm......
emmmm......
没有爱酱早安的一天一定也会很好吧,嗯,一定......