Chef and Queries |
As part of his daily job, Chef has to solve problems involving sets. Till now, Chef has been using inefficient methods to solve his set related problem, wasting a lot of his precious time. He has agreed to pay you a lot of money for solving the following problem for him efficiently.
First, Chef needs to perform Q operations on a set. Each operation is either:
- 1. Add a number to the set (if this number is NOT already present in the set).
- 2. Erase a number from the set (if this number exists in the set).
- 1 ≤ Q ≤ 107
- 1 ≤ S1, A, B ≤ 109
Then, he needs to find the sum of all elements of the set after performing these Q queries. Your job is to find this sum for him quickly.
Input
The first line of input contains four integers — Q, S1, A, B. S1 is the first number in the operations. Aand B are special constants explained later.
Every operation Si is represented by a single integer. If Si is odd, then it represents the first operation, otherwise the second type, and in both of them the integer you have to add/delete equals [Si / 2], where [] is the greatest integer (or floor) function.
Si = (A*Si-1 + B) mod 232 when i > 1.
Note: In this problem, the time limit is very tight. Using built-in data structures, such as set/unordered_set in C++ or TreeSet/HashSet in Java, may lead to a Time Limit Exceed verdict.
Output
Output a single line containing a single integer — sum of elements in the set after Q queries.
Constraints
Example
Input: 5 1 1 1 Output: 3 Input: 10000000 777777777 777777777 777777777 Output: 5362358669068782
Explanation:
The sequence {Si} is 1, 2, 3, 4, 5:
Operation 1, 1 mod 2 = 1, add number [1 / 2] = 0 to set, sum is 0.
Operation 2, 2 mod 2 = 0, erase number [2 / 2] = 1 from set, 1 is not in set, so nothing happens, sum is 0.
Operation 3, 3 mod 2 = 1, add number [3 / 2] = 1 to set, sum is 1.
Operation 4, 4 mod 2 = 0, erase number [4 / 2] = 2 from set, 2 is not in set, so nothing happens, sum is 1.
Operation 5, 5 mod 2 = 1, add number [5 / 2] = 2 to set, sum is 3.
==================================EDITORIAL====================================
DIFFICULTY:
Easy-Medium
PREREQUISITES:
Hash-Table
PROBLEM:
Given two types of queries:
1. Add the number to the set of numbers being maintained. 2. Remove the given number from the set if it exists in it.
1. Add the number to the set of numbers being maintained. 2. Remove the given number from the set if it exists in it.
The numbers to be inserted/deleted are generated according to the following scheme:
= (a* + b) mod ,
where and are integers.
= (a* + b) mod ,
where and are integers.
The sum of the numbers finally remaining in the set after all the operations is to be reported.
EXPLANATION:
Given the number of operations to be executed, i.e., , it should be clear that the insertions and deletions from the set are to be done in . Use of STL or pre-written libraries in C++/Java can't be used since they will definitely time out because of associated overheads.
Hash Table Solution One way is to write our own hash table. Editorialist's solution provides a standard implementation of Hash-Table with chaining to handle collision. For chaining, linked list has been used in the given solution. You can read more about it over the internet.
Bitset Solution A neater and more concise solution is using Bitset. Let's think about the naive solution to this problem first. If we could simply keep an array of length , then direct insert/lookup in the array would have been possible. The the memory constraints don't allow that big an array. However, let us look at the constraints on the number being inserted/deleted into the set. We know they lie between 0 and , i.e., they can be represented by 31 bits. Now, we can use a smart way to index numbers. Let us keep an array of length . This is perfectly fine with the memory limits. Now, for a 31 bit integer , let the first 26 bits indicate the index in the array where will reside. The rest 5 bits can be encoded in a 32 bit integer since only different possibilities exist. Please read setter's/tester's solutions for this approach.
There is one more intricacy here: calculating . If we use the normal operation present in some of the programming languages, the solution will exceed time limit. This is because is a complex operation and performing it times will not work. The observation is that we have to take . If we keep the data type of , , to be unsigned, in that case, we will not have to use operation because the range of unsigned int is to . Thus, if goes over it will automatically overflow around to greater than . In other words, the compiler will perform the function implicitly because of the overflow.
COMPLEXITY:
per insert and delete operation.
=========================================code===============================
- #include <cstdio>
- #include <iostream>
- #include <cmath>
- #include <string>
- #include <list>
- #include <vector>
- #include <algorithm>
- #include <functional>
- #include <utility>
- #include <set>
- #include <map>
- #include <complex>
- #include <queue>
- #include <stack>
- #include <cstdlib>
- #include <ctime>
- #include <cstring>
- #include <string.h>
- using namespace std;
- typedef unsigned int uint;
- typedef long long int64;
- typedef unsigned long long uint64;
- typedef unsigned short ushort;
- typedef unsigned char uchar;
- typedef pair<int,int> ipair;
- typedef vector<int> VI;
- typedef vector<string> VS;
- typedef vector<double> VD;
- #define SIZE(A) ((int)(A.size()))
- #define LENGTH(A) ((int)(A.length()))
- #define MP(A,B) make_pair(A,B)
- const double eps=1e-11;
- #define FOR(i,a,b) for(int i=(a);i<(b);++i)
- #define REP(i,a) for(int i=0;i<(a);++i)
- #define ALL(a) (a).begin(),(a).end()
- int64 s;
- uint w[1<<26];
- void add(uint n)
- {
- uint b=(((uint)1)<<(n&31));// finding which bit is it out or 32 bits
- uint m=(n>>5);// index calculation which is least 26 bits
- if (!(w[m]&b)) { s+=n; w[m]|=b; }
- }
- {
- uint b=(((uint)1)<<(n&31));// finding which bit is it out or 32 bits
- uint m=(n>>5);// index calculation which is least 26 bits
- if (w[m]&b) { s-=n; w[m]^=b; }
- }
- int main()
- {
- std::ios_base::sync_with_stdio(false);
- int q;
- uint s1,a,b;
- cin>>q>>s1>>a>>b;
- s=0;
- REP(step,q)
- {
- if (step>0) s1=a*s1+b;
- if (s1&1)
- {
- uint v=s1>>1;
- // cout<<"add"<<s1<<" "<<v<<endl;
- add(s1/2);
- }
- else
- {
- uint v=s1>>1;
- // cout<<"remove "<<s1<<" "<< v<<endl;
- }
- }
- cout<<s<<endl;
- return 0;
- }