I want to find the sum of bitwise OR of all possible subarrays of a given array.
This is what I did till now:
from operator import ior
from functools import reduce
n = int(input())
a = list(map(int, input().split()))
total = 0
for i in range(1,n+1):
for j in range(n+1-i):
total += reduce(ior, a[j:j+i])
print(total)
But it is quite slow. How can I optimise it?
Since this question is from competition, I haven't answered till now.
Code:
#include <bits/stdc++.h>
using namespace std;
#define size 32
#define INT_SIZE 32
typedef long long int Int;
typedef unsigned long long int Unt;
// Driver code
int main()
{
Int n;
cin>>n;
Int arr[n];
for(int i=0;i<n;i++)
cin>>arr[i];
int zeros[size];
for(int i=0;i<size;i++)
zeros[i]=1;
unsigned long long int sum=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<size;j++)
{
if(!(arr[i] & 1))
zeros[j]++;
else
{
sum+=(Unt)((Unt)zeros[j]*(Unt)(1<<j)*(Unt)(n-i));
zeros[j]=1;
}
arr[i]>>=1;
}
}
cout<<sum;
return 0;
}
Logic:
Note*: This is my thinking process, this may not be understandable easily. Apology if I can't able to make you understand.
Take example :
5 (size of array)
1 2 3 4 5 (array)
for,
1 = 1.0
1,2 = 1.0 & 2.1
1,2,3 = 1.0 & 2.1 [3.0 & 3.1 won't be useful because they're already taken by 1 & 2]
1,2,3,4 = 1.0 & 2.1 & 4.2
1,2,3,4,5 = 1.0 & 2.1 & 4.2 are useful.
In above explanation, X.Y means Yth bit in number X is taken for OR operation.
For,
2 = 2.1
2,3 = 2.1 & 3.0 [Since 1.0 won't be available]
{continues..}
So, if you carefully observe although 3.0 is available, it's not being used while 1 is present.
If a bit needed to be used, same bit of previous numbers should be 0. [remember this, we'll use it later]
We'll create 1 array, named zeros, which gives count of last set bit of previous numbers at each position respectively [this sentence may give you confusion, try to read more, you may get clarity].
For given array,
At 1: 0 0 0
At 2: 1 1 0 {binary of 1 is 001}
At 3: 2 0 1 {binary of 2 is 010}
At 4: 3 0 0 {binary of 3 is 011}
At 5: 0 1 1 {binary of 4 is 100}
End: 0 2 0 {binary of 5 is 101}
What we did above is, if bit is set bit, we'll make it 0, else we add count so that we can understand how many numbers doesn't have set bit position wise respectively, means, before 3, 2 numbers doesn't have set bit at postion 2^2, 1 number doesn't have set bit at 2^0.
Now, we just need to multiply depending on their set bits.
If it is set bit, then we'll add (zeros[i]+1)(2^i)(n-i).
Let's first find the sum of bitwise OR of subarrays ending at position i. Let the OR of all the array elements from 1 to i is or and the ith element be a[i], the bits which are not set in a[i] but set in or are coming from some previous elements,
let's take an example here,
1 2 2
at position 3, or = 3, a[i] = 2, or^a[i] = 1
this means 1 is coming from some previous element if we remove 1 OR of some subarray ending at i will be reduced. last position where bit 0 is on is 1.
So the ans is,
ans = or*i
for all bits from 0 to m,
ans -= (i - lastposition[bit])*(1 << bit); //lastposition[] gives the last index at which bit is on.
Why last position? Beacuse the indexes before lastposition[], where this bit is on, will have no impact as the OR be reamin same due to the presence of this bit at lastposition[].
Final answer can be found out by summing up all the answers of 1 <= i <= n .
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define rep(i,a,b) for(int i = a; i <= b; i++)
using namespace std;
ll r, a, sum, pos[30];
int main()
{
int n;
cin >> n;
rep(i,1,n)
{
cin >> a;
r |= a;
ll ex = r^a;
ll ans = i*r;
rep(bit,0,30)
if(ex & (1 << bit))
ans -= ((ll)(i - pos[bit])* ((ll)1 << bit));
sum += ans;
rep(bit,0,30)
if(a & (1 << bit))
pos[bit] = i;
}
cout << sum << '\n';
}
Related
I am trying to rewrite a fibonacci algorithm from python to C, but am having some problems. Below is the algorithm in python and I get the correct answer, but after writing in C:
def fib(n):
a, b = 1,1
for i in range(n):
a, b = a+b, a
print(a, b)
return b
print(fib(8))
When I wrote it in C, I get the powers of 2 - I am not sure how and if possible to correct it.
#include<stdio.h>
int fib(n){
int a = 1;
int b = 1;
for (int i=0; i<n; i++){
a = a+b;
b = a;
}
return b;
}
int main(void){
int n;
printf("Enter the # of the fibonacci number in sequence:");
scanf("%d", &n);
int r = fib(n);
printf("%d\n", r);
}
Just add a 3rd variable for extra handling
#include <stdio.h>
int fib(int n) {
int a, b, c;
a = 0;
b = 1;
c = 0;
for (int i = 0; i < n; i++) {
a = b+c;
b = c;
c = a;
}
return a;
}
int main() {
int n;
n = fib(10); // 55
printf("%d\n", n);
}
Zero is a Fibonacci number too!
Try:
int fib(int n){
int a = -1;
int b = 1;
for (int i = 0; i < n; i++) {
int t = a + b;
a = b;
b = t;
}
return b;
}
Also, none of the answers so far (including this one) account for signed integer overflow which is undefined in C. Though, for a trivial program like this it's okay to ignore it. When n is greater than 47 it overflows on my pc.
It can be done with just two variables with a simple change b = a-b. However, an optimizing compiler will use a third register as a temp variable instead of doing b = a - b;
#include<stdio.h>
int fib(n){
int a = 1;
int b = 0;
for (int i = 0; i < n; i++){
a = a+b;
b = a-b;
}
return b;
}
int main(void){
int n;
printf("Enter the # of the fibonacci number in sequence:");
scanf("%d", &n);
int r = fib(n);
printf("%d\n", r);
return 0;
}
In Python, when a multiple assignment statement is executed, all expressions on the right-hand side are evaluated using the current values of the variables, and then these values are bound to the variables given in the left-hand side. For example, the statement
a, b = a+b, a
evaluates both the expressions a+b and a, using the current values of a and b, and then binds these values to a and b, respectively. If the current values are a=1, b=1, then the expressions have values 1+1=2 and 1, respectively, and so we get a=2, b=1.
However, your C code executes the two statements a=a+b and b=a in sequence, rather than in parallel (like Python does). First the expression a+b is evaluated (if a=1, b=1, then a+b=2), and its value is bound to the variable a (so a is 2), and finally the expression a in the second statement is evaluated (it has value 2), and its value is bound to b (so b=2). If you want to use the original value of a (a=1) in the statement b=a, then you must store that original value in a temporary variable before overwriting a by a+b, as follows:
temp=a;
a=a+b;
b=temp;
In general, you can figure out yourself what is wrong with the program by learning to do a hand simulation of the program, where you write down (on paper) the current values of each variable in the program. For example, you can write the variables a and b in separate lines, with their initial values 1 and 1, respectively, next to them. Each time you execute an assignment statement, evaluate the expression on the right-hand side using the current values, and overwrite the left-hand-side variable with this new value. So, when you encounter a=a+b, you would evaluate a+b to be 2 (using the current values), and then cross out the current value of 1 for a and replace it by 2. In this manner, you can obtain the output using pencil and paper, and figure out what is wrong with the program.
Recently i came across a problem, given 2 integers A and B, we need to convert A to B in minimum number of steps.
We can perform following operations on A:
If A is odd, decrease by 1
If A is even, increase by 1
Multiply A(even or odd) by 2
if A is even, divide by 2
again, we have to find the minimum number of steps needed to convert A to B.
The constraints are 0 < A, B < 10^18
My approach:
I tried to solve the problem using Breadth First Search, adding all the possible reachable numbers from a step into a queue, but it fails on higher constraints i.e. time outs.
Can anyone suggest a faster alternative?
EDIT: A is not necessarily less than B
Basically you have the following operations:
flip the lowest bit
shift bits to the left or to the right
Assume, you have A == 0, how you would construct B? Right, you flip the lower bit one by one and shift the number to the left, for example if B == 5, which is 0x0101, you will need 2 flips and 2 shifts.
Now, we have to deal with the case when A != 0 -- in this case you have to turn the lower bit to 0 and shift right to clean up the mess. For example, if you have A == 32, which is 0x0100000 and you want to get 5 (0x0101), you have to do three shifts to the right, then flip the lower bit and you're done.
So, all you have to do is to:
count how many flips/r-shifts you have to do until the highest bit of A is equal to the highest bit of B.
then count how many flips/r-shifts you need to clean up the rest
count how many flips/left-shifts you need to rebuild the lower part of B.
ok, a few hours passed, here's the solution. First a useful function, that says how many ops we need to create a number:
def bit_count(num) :
# the number of non-zero bits in a number
return bin(num).count('1')
def num_ops(num) :
# number of shifts + number of flips
return num.bit_length() + bit_count(num)
Now, well, assume A > B, because otherwise we can swap them while keeping the number of the operations the same. Here's how far we have to shift A to make it start from the same bit as B:
needed_shifts = A.bit_length() - B.bit_length()
while doing that we need to flip a few bits:
mask = (1 << (needed_shifts+1)) - 1
needed_flips = bit_count(A & mask)
Now we count how many ops are required to clean A and rebuild B:
A >>= needed_shifts
clean_shifts = (A & ~B).bit_length()
clean_flips = bit_count(A & ~B)
rebuild_shifts = (B & ~A).bit_length()
rebuild.flips = bit_count(B & ~A)
Finally we sum up all together:
result_ops = needed_shifts + needed_flips + max(clean_shifts,rebuild_shifts) * 2 + clean_flips + rebuils_flips
That's all, folks! =)
The list of available operations is symmetric: 2 sets of operations, each the opposite of the other:
the last bit can be flipped
the number can be shifted left one position or right one position if the low bit is 0.
Hence it takes the same number of operations to go from A to B or from B to A.
Going from A to B takes at most the number of operations to go from A to 0 plus the number of operations to go from B to 0. These operations strictly decrease the values of A and B. If along the way an intermediary value can be reached from both A and B, there is no need to go all the way to 0.
Here is a simple function that performs the individual steps on A and B and stops as soon as this common number is found:
def num_ops(a, b):
# compute the number of ops to transform a into b
# by symmetry, the same number of ops is needed to transform b into a
count = 0
while a != b:
if a > b:
if (a & 1) != 0:
a -= 1
else:
a >>= 1
else:
if (b & 1) != 0:
b -= 1
else:
b >>= 1
count += 1
return count
This problem can be optimised using dynamic programming.
I wrote the following code taking few things into consideration:
The infinite recursion should be avoided carefully by putting up base conditions. For eg: if A=0 and B<0, then no answer exists.
If the function convert(A, B) is called for more than 1 times into recursion and answer for the state (A, B) is not previously calculated, then recursion is terminated as no answer exists for this case. For eg: (80, 100) -> (160, 100) -> (80->100) -> (160, 100) -> ........
This is done by maintaining the count of each state into a map and defining the maximum recursive calls limit (3 in the following program) for the same state of DP.
The map dp maintains the answer for each state (A, B) and the map iterationsCount maintains the count of number of times the same state (A, B) is called.
Have a look at the following implementation:
#include <utility>
#include <iterator>
#include <map>
#include <set>
#include <iostream>
#include <climits>
typedef long long int LL;
std::map<std::pair<LL, LL>, LL> dp;
std::map<std::pair<LL, LL>, int > iterationsCount;
LL IMPOSSIBLE = (LL)1e9;
LL MAX_RECURSION_LIMIT = 3;
LL convert(LL a, LL b)
{
//std::cout<<a<<" "<<b<<std::endl;
// To avoid infinite recursion:
if(iterationsCount.find(std::make_pair(a, b))!=iterationsCount.end() &&
iterationsCount[std::make_pair(a,b)] > MAX_RECURSION_LIMIT &&
dp.find(std::make_pair(a,b))==dp.end()){
return IMPOSSIBLE;
}
// Maintaining count of each state(A, B)
iterationsCount[std::make_pair(a, b)]++;
LL value1, value2, value3, value4, value5;
value1 = value2 = value3 = value4 = value5 = IMPOSSIBLE;
if(dp.find(std::make_pair(a,b)) != dp.end()){
return dp[std::make_pair(a, b)];
}
// Base Case
if(a==0 && b<0){
return IMPOSSIBLE;
}
// Base Case
if (a == b)
return 0;
//Conditions
if (a%2 == 1){
if(a < b){
value1 = 1 + convert(2*a, b);
}
else if(a > b){
value2 = 1 + convert(a-1, b);
}
}
else{
if(a < b){
value3 = 1 + convert(a*2, b);
value4 = 1 + convert(a+1, b);
}
else if(a > b){
value5 = 1 + convert(a/2, b);
}
}
LL ans = std::min(value1, std::min(value2, std::min(value3, std::min(value4, value5))));
dp[std::make_pair(a, b)] = ans;
return ans;
}
int main(){
LL ans = convert(10, 95);
if(ans == IMPOSSIBLE){
std::cout<<"Impossible";
}else{
std::cout<<ans;
}
return 0;
}
I am tasked with calculating hamming distances between 1D binary arrays in two groups - a group of 3000 arrays and a group of 10000 arrays, and every array is 100 items(bits) long. So thats 3000x10000 HD calculations on 100 bit long objects.And all that must be done in at most a dozen minutes
Here's the best of what I came up with
#X - 3000 by 100 bool np.array
#Y - 10000 by 100 bool np.array
hd = []
i=1
for x in X:
print("object nr " + str(i) + "/" + str(len(X)))
arr = np.array([x] * len(Y))
C = Y^arr # just xor this array by all the arrays in the other group simultainously
hd.append([sum(c) for c in C]) #add up all the bits to get the hamming distance
i+=1
return np.array(hd)
And it's still going to take 1-1.5 hours for it to finish. How do I go about making this faster?
You should be able to dramatically improve the summing speed by using numpy to perform it, rather than using a list comprehension and the built-in sum function (that takes no advantage of numpy vectorized operations).
Just replace:
hd.append([sum(c) for c in C])
with:
# Explicitly use uint16 to reduce memory cost; if array sizes might increase
# you can use uint32 to leave some wiggle room
hd.append(C.sum(1, dtype=np.uint16))
which, for a 2D array, will return a new 1D array where each value is the sum of the corresponding row (thanks to specifying it should operate on axis 1). For example:
>>> arr = np.array([[True,False,True], [False,False,True], [True, True,True]], dtype=np.bool)
>>> arr.sum(1, np.uint16)
array([ 2, 1, 3], dtype=uint16)
Since it performs all the work at the C layer in a single operation without type conversions (instead of your original approach that requires a Python level loop that operates on each row, then an implicit loop that, while at the C layer, must still implicitly convert each numpy value one by one from np.bool to Python level ints just to sum them), this should run substantially faster for the array scales you're describing.
Side-note: While not the source of your performance problems, there is no reason to manually maintain your index value; enumerate can do that more quickly and easily. Simply replace:
i=1
for x in X:
... rest of loop ...
i+=1
with:
for i, x in enumerate(X, 1):
... rest of loop ...
and you'll get the same behavior, but slightly faster, more concise and cleaner in general.
IIUC, you can use np.logical_xor and list comprehension:
result = np.array([[np.logical_xor(X[a], Y[b].T).sum() for b in range(len(Y))]
for a in range(len(X))])
The whole operation runs in 7 seconds in my machine.
0:00:07.226645
Just in case you are not limited to using Python, this is a solution in C++ using bitset:
#include <iostream>
#include <bitset>
#include <vector>
#include <random>
#include <chrono>
using real = double;
std::mt19937_64 rng;
std::uniform_real_distribution<real> bitset_dist(0, 1);
real prob(0.75);
std::bitset<100> rand_bitset()
{
std::bitset<100> bitset;
for (size_t idx = 0; idx < bitset.size(); ++idx)
{
bitset[idx] = (bitset_dist(rng) < prob) ? true : false;
}
return std::move(bitset);
}
int main()
{
rng.seed(std::chrono::high_resolution_clock::now().time_since_epoch().count());
size_t v1_size(3000);
size_t v2_size(10000);
std::vector<size_t> hd;
std::vector<std::bitset<100>> vec1;
std::vector<std::bitset<100>> vec2;
vec1.reserve(v1_size);
vec2.reserve(v2_size);
hd.reserve(v1_size * v2_size); /// Edited from hd.reserve(v1_size);
for (size_t i = 0; i < v1_size; ++i)
{
vec1.emplace_back(rand_bitset());
}
for (size_t i = 0; i < v2_size; ++i)
{
vec2.emplace_back(rand_bitset());
}
std::cout << "vec1 size: " << vec1.size() << '\n'
<< "vec2 size: " << vec2.size() << '\n';
auto start(std::chrono::high_resolution_clock::now());
for (const auto& b1 : vec1)
{
for (const auto& b2 : vec2)
{
/// Count only the bits that are set and store them
hd.emplace_back((b1 ^ b2).count());
}
}
auto time(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start).count());
std::cout << vec1.size() << " x " << vec2.size()
<< " xor operations on 100 bits took " << time << " ms\n";
return 0;
}
On my machine, the whole operation (3000 x 10000) takes about 300 ms.
You could put this into a function, compile it into a library and call it from Python. Another option is to store the distances to a file and then read them in Python.
EDIT: I had the wrong size for the hd vector. Reserving the proper amount of memory reduces the operation to about 190 ms because relocations are avoided.
I have an array in python, which is declared as follow:
u[time][space]
My code in Python's for loop requires me to do the following:
for n in range(0,10):
u[n][:] = 1
This colon indicates the whole range of my [space].
Now, how would I go about to use the colon (:) to indicate the whole range when doing for loop in c++?
Thanks
for(auto& inner : u)
std::fill(inner.begin(), inner.end(), 1);
Use two loops as suggested.
Something like:
int n, s;
for(n=0; n<10; n++){
for(s=0; s<space; s++){
u[n][s] = 1;
}
}
should work.
C++ does not have an equivalent to
for n in range(0,10):
u[n][:] = 1
You are going to have to write the loop that u[n][:] = 1 represents. Fortunately with ranged based for loops it is pretty trivial. That would look like
int foo[3][3];
for (auto& row : foo)
for (auto& col : row)
col = 1;
I don't remember a quick way to do it in C++. I'm afraid you'd have to loop in each table.
This would look like this (admitting that space is a known integer):
for (int i = 0; i < 10; i++)
for (int j = 0; j < space; j++)
u[i][j] = 1;
You're going to have to use two loops. Modern C++ has some tricks up its sleeve to make initializing these loops simple, but here is a basic C example that will work anywhere:
#define TIME_MAX 100
#define SPACE_MAX 350
int u[TIME_MAX][SPACE_MAX];
int i, j;
for (i = 0; i < TIME_MAX; i++)
for (j = 0; j < SPACE_MAX; j++)
u[i][j] = 1;
I have a list of integers which is being continuously modified in a loop and I need to tell if its content repeats itself after a certain amount of iterations to break the loop.
If it doesn't, the list will eventually modify to [] or the loop terminates when a certain limit of iterations is reached. My solution so far:
def modify(numlist, a, b):
numlist = [(x * a) for x in numlist]
for i in range((len(numlist) - 1), 0, -1):
if numlist[i] >= b: numlist[i - 1] += numlist[i] // b
numlist[i] = numlist[i] % b
numlist[0] %= b
while numlist[-1] == 0:
numlist.pop(-1)
if numlist == []: break
numlist = [1, 2, 3, 4, 5]
listHistory = [numlist]
a, b = someValue, anotherValue
n = 0
while numlist != [] and n <= limit:
modify(numlist, int(a), int(b))
listHistory.append(numlist)
if numlist in listHistory: break
n += 1
limit can be very large (ca. 10**6 - 10**7) and checking the current numlist against all its previous versions becomes really slow.
Is there a more efficient way to do this or even a method to predetermine if the modification is periodic by the lists initial content and given a, b?
OK, got something.
If you look at the last element in your list, lets call it m. What happens to it it gets multiplied by a and then taken modulo b. It never gets mixed with any other element, so if a configuration of the list has to repeat itself the following must hold:
m*a^n=m modulo b
<==>a^n=1 modulo b
< >a^(n+1)=a modulo b
This is a problem where you can make use of Fermats little theorem
If a and b are coprimes, then
a^phi(b)=1 modulo b
where phi is Eulers totient function.
So this reduces the amount of list configurations which you have to store in your history drastically. You only have to store it every phi(b) steps.
I found an implementation of phi here:
Computing Eulers Totient Function
UPDATE:
Ok, I found a quick solution if you were to do += list[i] % b instead of += list[i] // b. Otherwise you need b^4*phi(b) steps in the worst case
UPDATE2:
I rewrote the code in C (see below) to make it faster and implemented the "tortoise and the hare" algorithm proposed by #user2357112. This way i can check some million loops per second what should be way faster than the python implementation.
I tried it for some different value combinations:
a b steps b^4*phi(b) (b/GCD(b,a))^4*phi(b/GCD(n,a)) (b/GCD(b,a))^4*phi(b/GCD(n,a))/steps
2 37 67469796 67469796 67469796 1
3 37 33734898 67469796 67469796 2
4 37 33734898 67469796 67469796 2
5 37 67469796 67469796 67469796 1
6 37 7496644 67469796 67469796 9
7 37 16867449 67469796 67469796 4
36 37 3748322 67469796 67469796 18
2 36 39366 20155392 629856 16
3 36 256 20155392 82944 27648
4 36 19683 20155392 39366 2
5 36 5038848 20155392 20155392 4
So you see where this is going: The cycle length seems always to be a divisor of (b/GCD(b,a))^4*phi(b/GCD(n,a)), so the worst case is (b/GCD(b,a))^4*phi(b/GCD(n,a)) steps as suspected
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void modify(int *, int, int);
void printl(int * );
int main(int argc, const char*argv[])
{
int l[5]={1,2,3,4,5};
int lz[5]={1,2,3,4,5};
int i=1,a,b,n;
if (argc<4) {
printf("Not enough arguments!!\n");
exit(1);
}
a=atoi(argv[1]);
b=atoi(argv[2]);
n=atoi(argv[3]);
modify(l,a,b);
while (i<n) {
modify(l,a,b);
modify(l,a,b);
modify(lz,a,b);
i++;
if (memcmp(l,lz,sizeof(l))==0) {
printf("success!\n");
break;
}
if (i%1000000==0) printf("Step %d.000.000\n",i/1000000);
}
printf("Final step: %d\n",i);
printl(l);
printl(lz);
return 0;
}
void modify(int * li, int a, int b) {
int i=0;
while (i<=4) {
li[i]*=a;
i++;
}
i=4;
while (i>=1) {
if (li[i]>=b) {
li[i-1]+=li[i]/b;
}
li[i]=li[i]%b;
i--;
}
li[0]=li[0]%b;
}
void printl(int * li) {
printf("l=(%d,%d,%d,%d,%d)\n",li[0],li[1],li[2],li[3],li[4]);
Your list (which you really ought to rename, by the way) stores a number mod b**something in base b. Every run of modify multiplies the number by a, then truncates zeros at the end of the representation.
Call the number originally represented by the list n, and call the original length of the list l. If this process terminates, it will do so at the first iteration k such that b**l divides n * a**k, which will only ever occur if and only if all prime factors of b**l / gcd(n, b**l) are factors of a. This is simple to determine:
def all_prime_factors_of_first_divide_second(a, b):
while a != 1:
factor = gcd(a, b)
if factor == 1:
return False
while not a % factor:
a //= factor
return True
First please allow me to say, all lists are periodic, if you consider a large enough period.
That said, this might be a good place to use a bloom filter, EG:
https://pypi.python.org/pypi/drs-bloom-filter/
Bloom filters are sets that can perform set membership tests pretty quickly, and can add things to the set without actually storing the data of the element. This means it's probabilistic, but you can adjust the probability. So you might use a bloom filter test for a quick check, and upon detecting a match using the bloom filter, confirm the result using your slow+deterministic algorithm.
Usage looks like:
In [1]: import bloom_filter_mod
In [2]: bloom_filter = bloom_filter_mod.Bloom_filter(1000000, 0.01)
In [3]: for i in range(10):
...: bloom_filter.add(i)
...:
In [4]: for i in range(0, 20, 2):
...: if i in bloom_filter:
...: print('{} present'.format(i))
...:
0 present
2 present
4 present
6 present
8 present
The 1000000 is the maximum number of elements you want to store in the filter, and the 0.01 is the maximum probability of a false positive when full.
So you could "store" each subsequence in the filter, and quickly detect recurrences.