报数游戏 题解
题目id:
题目描述
温老师为了带小朋友们巩固小学数学知识,特地设计了一个报数游戏。 小朋友们在\(n\)块空地上玩报数游戏,遵循如下规则
- 每个小朋友手里都有一个写了数字的纸条,在报数的时候需要将纸条上的数字报出来
- 报数最小的小朋友们离开场地
- 每个小朋友都会做数学计算,在一轮游戏报数最小的小朋友们离场之后,剩余的所有小朋友会将手里的纸条上的数字减去刚刚离场的小朋友们纸条上的数字。并作为新的报数的数字。
这个游戏一直持续到所有小朋友都离场才会结束,现在请你输出最多可以进行报数游戏的轮次。
解题思路
这题看上去是做\(n\)次模拟,可是时间复杂度为\(O(n^2)\),数据不允许(\(1\leq n\leq 10^6\))。
其实根据以下三点:
- 每次会减去相同的数,相当于每个小朋友数字大小从某种意义上说是不变的
- 拿着当前最小数的小朋友又会在\(1\)轮之内离场
- 数字为\(0\)的地方是空地
可以得出一个结论:答案为去重后的非零元素数量。
那么这条结论是怎么来的呢?
根据第一点,可以得出只要有两个小朋友手里拿的数字不同,那么就要多报一轮(差不同)
再根据第二点,执行上面一条的前提是需要将所有数字去重
最后根据第三点,我们不能考虑\(0\)
所以答案为去重后的非零元素数量。
用一个\(set\)就可以解决。
AC Code
#include<bits/stdc++.h>
#define N 1000007
#define INF 1e18
#define MOD 998244353
#define LL long long
#define pb push_back
#define lb long double
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define IOS ios::sync_with_stdio(0),cin.tie(nullptr),cout.tie(nullptr)
using namespace std;
LL n;
set<LL>s;
int main()
{
IOS;
cin>>n;
for(LL i=1,a;i<=n;++i)
{
cin>>a;
if(a!=0)
s.insert(a);
}
cout<<(LL)(s.size());
return 0;
}