Problem Statement
You are given an integer sequence A=(A_1,A_2,\ldots,A_N)A=(A1,A2,…,AN) of length NN.
Perform the following operation MM times:
- For each i\ (1\leq i \leq N)i (1≤i≤N), add ii to A_iAi. Then, find the minimum non-negative integer not contained in AA.
Constraints
- 1\leq N,M \leq 2\times 10^51≤N,M≤2×105
- -10^9\leq A_i\leq 10^9−109≤Ai≤109
- All values in the input are integers.
题目大意是有一串数字,每一轮会给每个数字加上自身号次对应的数字,需要找出每一轮这些数字中没有出现过的最小的非负整数。
一开始当然是直接想到了最暴力的方法,直接模拟每一轮然后找数字,当然是肯定不行的,所以直接看了别人的,发现需要用到一点预处理的思路。
首先要知道符合条件的数字一定在[0,n]这个区间之内,因为最坏的情况是n个数字按照公差为1的等差数列排列,这时候要么是0,要么是n,其他情况一定是在区间(0,n)里面的数字,所以我们只要考虑每个数字在这个区间内的情况。
所以对于任意的一轮,需要只要考虑所有可以落在这个区间内的数字的情况,所以在一开始的预处理,我们就需要把每个数字作为有效值出现在某一轮的值记录下来,比如n为10,a[7]为-2,那么a[7]的有效值是5(在[0,10]之内的值),出现在第一轮,那么第一轮的5就需要标记为有(利用set实现)。
预处理之后,留下的数据量其实就比较小了,对于任意的a[i],实际上有效的数字个数是n/i,最终在每一轮开始从0开始找,找到没出现的就直接输出结果就好。
代码如下:
#include<stdio.h>
#include<algorithm>
#include<set>
using namespace std;
#define ll long long
int a[2000000];
set<int>st[500000];
int main()
{
int m,n;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", a + i);
//先维护
for (int i = 1; i <= n; i++)
{
//先看在m轮里面这个数字能不能落在[0,n]
int num = 0;//表示贡献的轮数
if (a[i] < 0)
{
num += ((-a[i]) - 1) / i + 1;
a[i] += num * i;
}
while (num <= m && a[i] <= n)
{
st[num].insert(a[i]);
a[i] += i;
num++;
}
}
//开始查找
for (int i = 1; i <= m; i++)
{
for (int j = 0; j <= n; j++)
{
if (!st[i].count(j))
{
//表示数字为0
printf("%d\n", j);
break;
}
}
}
return 0;
}#include<stdio.h>
#include<algorithm>
#include<set>
using namespace std;
#define ll long long
int a[2000000];
set<int>st[500000];
int main()
{
int m,n;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", a + i);
//先维护
for (int i = 1; i <= n; i++)
{
//先看在m轮里面这个数字能不能落在[0,n]
int num = 0;//表示贡献的轮数
if (a[i] < 0)
{
num += ((-a[i]) - 1) / i + 1;
a[i] += num * i;
}
while (num <= m && a[i] <= n)
{
st[num].insert(a[i]);
a[i] += i;
num++;
}
}
//开始查找
for (int i = 1; i <= m; i++)
{
for (int j = 0; j <= n; j++)
{
if (!st[i].count(j))
{
//表示数字为0
printf("%d\n", j);
break;
}
}
}
return 0;
}