题面:https://codeforces.com/contest/1294/problem/D
题目大意:
每次都会往你的数列里加一个值,你可以任意加减这个值若干次(但是只能加x或者减x)
然后问最小的不属于这个数列的非负整数是什么
你需要进行的操作是,让这个最小的不属于这个数列的非负整数最大
每次加一个值并且询问一遍
解题思路:
易得到,每一次输出的答案在进行完题目的贪心后会呈现上升趋势,且值最大只可能为序列内元素的个数
所以我们可以让每次加入的值在进行完若干次操作后尽量成为靠前的序列中还没出现过的数值,以助于答案能尽量变得更大
举题目的样例,不能按照Hint的思想去想,根据上述思想可以得到下面的步骤——
q=7,x=3
加入0,序列为[0],答案为1
加入1,序列为[0,1],答案为2
加入2,序列为[0,1,2],答案为3
加入2,因为2存在过,所以贪心让2变成尽量靠前的未出现的数,即5,所以序列为[0,1,2,5],答案为3
加入0,因为0存在过,所以贪心让0变成尽量靠前的未出现的数,即3,序列为[0,1,2,3,5],答案为4
加入0,因为0存在过,贪心让0变成尽量靠前的未出现的数,又因为3也出现过,所以为6,序列为[0,1,2,3,5,6],答案为4
加入10,10未出现过,变成尽量靠前的未出现的数,可得能够变成4,序列为[0,1,2,3,4,5,6],答案为7
经过以上操作,可以发现一个规律
不管怎么让新加进来的值d怎么变(+x/-x),d%x的值保持不变
所以可以想到用一个数组mini存不同的d%x这一类数字此时最小的未出现过的值
其后每次加进来一个值d,取mini[d%x]让这个数加进当前的序列内,然后让mini[d%x]+x成为下一个未出现过的数即可
如果mini[t]>q了,说明这一类的数字太多了,再加对答案也不会有贡献,就可以不考虑了
然后让答案作为一个变量,因为答案只增不减,每次就保持它的状态即可,在可以尝试增大时用
while(arr[ans])ans++;
来让他增大即可(arr数组判断数是否存在于序列内)
1 /* 2 Written By StelaYuri 3 On 2020/01/22 4 */ 5 #include<bits/stdc++.h> 6 using namespace std; 7 bool arr[400050];//判断i是否存在于当前的数列内 8 int mini[400050];//d%x的种类之下未出现在arr序列中的最小数 9 void solve(){ 10 int q,x,d,t,i,ans=0; 11 cin>>q>>x; 12 for(i=0;i<x;i++) 13 mini[i]=i; 14 for(i=0;i<q;i++){ 15 cin>>d; 16 t=d%x; 17 if(mini[t]<=q){ 18 arr[mini[t]]=true; 19 while(arr[ans]) 20 ans++; 21 mini[t]+=x; 22 } 23 cout<<ans<<‘\n‘; 24 } 25 } 26 int main(){ 27 ios::sync_with_stdio(0); 28 cin.tie(0);cout.tie(0); 29 solve(); 30 31 return 0; 32 }
或者简化下代码,意思不变,此时只要多进行取模运算即可
1 /* 2 Written By StelaYuri 3 On 2020/01/22 4 */ 5 #include<bits/stdc++.h> 6 using namespace std; 7 int arr[400050]; 8 void solve(){ 9 int q,x,d,t,i,ans=0; 10 cin>>q>>x; 11 while(q--){ 12 cin>>d; 13 arr[d%x]++; 14 while(arr[ans%x]){ 15 arr[ans%x]--; 16 ans++; 17 } 18 cout<<ans<<‘\n‘; 19 } 20 } 21 int main(){ 22 ios::sync_with_stdio(0); 23 cin.tie(0);cout.tie(0); 24 solve(); 25 26 return 0; 27 }
原文地址:https://www.cnblogs.com/stelayuri/p/12230033.html