SPOJ Problem KPRIMES2 - c++

I am new to this forum and not well aware of protocols of this forum so pardon me for my ignorance. My question is related to spoj problem https://www.spoj.pl/problems/KPRIMES2/. I am getting TIME LIMIT EXCEED for this problem.I think the bottleneck of this program is generating 10^9.Could some one suggest how to improve this sieve , faster way to generate prime or how to solve this problem. Here is sketch of my algorithm
This program generates all the primes of form 2k+1 and encoded these primes into 32 bit integers of array a[i] in which unset bit represents primes.a[0] encodes 3,5,7.......65.a[1] encodes 67 onwards and so on. I have taken a auxiliary array bitcnt[] , in which bitcnt[i] stores sum of unset bits of a[0], a[1],.........a[i]. I used bitcnt for binary search and find the position of kth number.Here is bit explanation of functions.
prime() function generated primes and i encoded the primes onto bits of number[32 bit unsigned integer]. bitcnt array stores sum of unset bits of array a for binary search purpose.
bsearchupper(int m) return index of bitcnt in which m lie.
Finally in main function , i am storing how many primes are upto upperbound of m and started decreasing value till i got K. Thank you.
Edit:Problem statement from SPOJ
Input
An integer stating the number of queries Q(equal to 100000), and Q lines follow, each containing one integer K between 1 and 50000000 inclusive.
Output
Q lines with the answer of each query: the Kth prime number.
Example
Input:
8
1
10
100
1000
10000
100000
1000000
10000000
Output:
2
29
541
7919
104729
1299709
15485863
179424673
#include<cstdio>
#include<vector>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<ctime>
#define Lim 1000000000
using namespace std;
unsigned int a[(Lim>>6)+10],bitcnt[(Lim>>6)+10];
int bound;
void prime()
{
int p_1,q_1,p_2,q_2,Ub=sqrt(Lim*1.0);
for(int i=3;i<=Ub;i+=2)
{
p_1=(i-3)>>6,q_1=((i-3)>>1)&31;
if(!(a[p_1] & (1L<<q_1)))
for(int j=i*i;j<Lim;j+=i)
if(j&1)
{
p_2=(j-3)>>6,q_2=((j-3)>>1)&31;
a[p_2]|=(1L<<q_2);
}
}
int cnt=0;bound=0;
for(int i=0; i<=((Lim>>6)-1);i++)
{
//p_1=(i-3)>>6,q_1=((i-3)>>1)&31;
cnt+=__builtin_popcount(~a[i]);
bitcnt[bound++]=cnt;
//cout<<bound-1<<"---"<<bitcnt[bound-1]<<endl;
}
//cout<<cnt<<endl;
}
int bsearchupper(int m)
{
int lo=0,hi=bound,mid;
while(lo<hi)
{
mid=lo+((hi-lo)>>1);
if(bitcnt[mid]<=m)lo=mid+1;
else hi=mid;
}
//cout<<"lo= "<<lo<<" mid= "<<mid<<" hi= "<<hi<<endl;
return lo;
}
int main()
{
//clock_t start,end;
//start=clock();
prime();
int t,k,c,ret,w;
for(scanf("%d",&t);t>0;t--)
{
scanf("%d",&k);
if(k==1) {cout<<"2"<<endl;continue;}
k=k-2;
c=bsearchupper(k);
ret=bitcnt[c],w=32*(c+1);
for(int i=31;i>=0;i--)
{
if(!(a[c] & (1L<<i)))
{
ret--;
if(ret==k) printf("%d\n",3+(w-1)*2);
}
w--;
}
}
//end=clock();
//cout<<((end-start)/(double)CLOCKS_PER_SEC)<<endl;
}

Consider compacting your prime storage even more. For example, in every block of 2*3*5*7*11=2310, there are exactly 1*2*4*6*10=480 numbers that have no prime factor of 11 or less, which you can pack into 15 array entries rather than (about) 36. That will eliminate a few hundred million bit operations sieving out those small factors. You'll have to change your indexing into the bit array; a couple of constant arrays of length 2310 giving the bit index (if it exists) and array element offset would help here, and a similar array (of length 480) converting bit positions back into values mod 2310.

Related

Reduce subsequence problem complexity from exponential to polynomial?

I am working on the following problem:
Given a set of non-negative distinct integers, and a value m, determine if there is a subset of the given set with sum divisible by m.
Input: The first line of input contains an integer T denoting the number of test cases. Then T test cases follow. The first line of each test case contains an integer N and M where N denotes the size of the array and M is the number for which we have to check the divisibility. The second line of each test case contains N space separated integers denoting elements of the array A[ ].
Output: If there is a subset which is divisible by M print '1' else print '0'.
I have tried a recursive solution:
#include <iostream>
#include<unordered_map>
using namespace std;
bool find_it(int a[],int &m,int n,int sum) {
if ((sum%m)==0 && sum>0)
return true;
if (n==0)
return false;
return find_it(a,m,n-1,sum) || find_it(a,m,n-1,sum-a[n-1]);
}
int main() {
int tc;
cin >> tc;
while (tc--) {
int n,m;
cin >> n >> m;
int a[n];
int sum = 0;
for (int i=0;i<n;i++) {
cin >> a[i];
sum += a[i];
}
bool answer = find_it(a,m,n,sum);
cout << answer << "\n";
}
return 0;
}
Which works fine and get accepted, but then I tried top-down approach, and am getting TLE ("Time Limit Exceeded"). What am I doing wrong in this memoization?
#include <iostream>
#include<unordered_map>
using namespace std;
bool find_it(
int a[], int &m, int n, int sum,
unordered_map<int,unordered_map<int,bool>> &value,
unordered_map<int,unordered_map<int,bool>> &visited){
if ((sum%m)==0 && sum>0)
return true;
if(n==0)
return false;
if(visited[n][sum]==true)
return value[n][sum];
bool first = false,second = false;
first = find_it(a,m,n-1,su1m,value,visited);
if(sum<a[n-1])
{
second=false;
}
else
second = find_it(a,m,n-1,sum-a[n-1],value,visited);
visited[n][sum] = true;
value[n][sum] = first || second;
return value[n][sum];
}
int main() {
int tc;
cin >> tc;
while (tc--) {
int n,m;
cin >> n >> m;
int a[n];
int sum = 0;
for (int i=0;i<n;i++) {
cin >> a[i];
sum+=a[i];
}
unordered_map<int,unordered_map<int,bool>> value;
unordered_map<int,unordered_map<int,bool>> visited;
cout << find_it(a,m,n,sum,value,visited) << "\n";
}
return 0;
}
Well, at first, you can reduce the problem to a modulo m problem, as properties of integers don't change when switching to modulo m field. It's easy to demonstrate that being divisible by m is the same as being identical to 0 mod m.
I would first convert all those numbers to their counterparts modulo m and eliminate repetitions by considering a_i, 2*a_i, 3*a_i,... until rep_a_i * a_i, all of them mod m. Finally you get a reduced set that has at most m elements. Then eliminate all the zeros there, as they don't contribute to the sum. This is important for two reasons:
It converts your problem from a Knapsack problem (NP-complete) on which complexity is O(a^n) into a O(K) problem, as its complexity doesn't depend on the number of elements of the set, but the number m.
You can still have a large set of numbers to compute. You can consider the reduced set a Knapsack problem and try to check (and further reduce it) for an easy-knapsack problem (the one in which the different values a_i follow a geometric sequence with K > 2)
The rest of the problem is a Knapsack problem (which is NP-complete) or one of it's P variants.
In case you don't get so far (cannot reduce it to an easy-knapsack problem) then you have to reduce the number of a_i's so the exponential time gets a minimum exponent :)
edit
(#mss asks for elaboration in a comment) Assume you have m = 8 and the list is 1 2 4 6 12 14 22. After reduction mod m the list remains as: 1 2 4 6 4 6 6 in which 6 is repeated three times. we must consider the three possible repetitions of 6, as they can contribute to get a sum, but not more (for the moment), let's consider 6*1 = 6, 6*2 = 12 and 6*3 = 18, the first is the original 6, the second makes a third repetition of 4 (so we'll need to consider 3 4s in the list), and the third converts into a 2. So now, we have 1 2 4 6 4 4 2 in the list. We make the same for the 4 repetitions (two 4 run into 8 which is 0mod m and don't contribute to sums, but we have to keep one such 0 because this means you got by repeated numbers the target m) getting into 1 2 4 6 0 4 2 => 1 2 4 6 0 0 2 =(reorder)=> 0 1 2 2 4 6 => 0 1 2 4 6. This should be the final list to consider. As it has a 0, you know a priori that there's one such sum (in this case you got is as including the two 4, for the original list's 4 and 12 numbers.
There is no need for value. Once you find a valid combination, i.e. if find_it ever returns true, you can just immediately return true in all recursive calls.
Some additional remarks:
You should use consistent indentation.
Variable sized arrays as in int a[n] are not standard C++ and will not work on all compilers.
There is no reason to pass m as int& instead of int.
A map taking boolean values is the same as a set where the element is assumed to map to true if it is in the set and false if it is not. Consider using unordered_set instead of unordered_map.
Composing two unordered_maps like this is expensive. You can just as easily put both keys into a std::pair and use that as key. This would avoid the overhead of maintaining the map.
bits/stdc++.h is also non-standard and you should specify the correct header files instead, e.g. #include <unordered_map> and #include <iostream>.
You should put spaces between the variable type and its name, even if the > from the template parameter allows it to parse correctly without. It makes code hard to read.

Prime number (SIGSEGV)

This is a very famous problem on SPOJ where you need to find prime numbers in a given range so the thing is the range lies from 1 to 1000000000.But every time i allocate an array of 1000000000 size it will give me a sigsegv error or a sigabrt error how do i overcome this problem of assigning very large values to an array
Apart from that i am using the sieve of ertosthenes algorithm to solve the problem.I have given the code below please help me resolve the problem by telling me what i need to change in my code so i don't get a sigsegv and sigabrt error.
#include<iostream>
#include<stdlib.h>
using namespace std;
int main()
{
int t,j;
long long int x,y;
cin>>t;
int i=0;
while(i<t)
{
cin>>x>>y;
long long int *a=new long long int[y];
for(int k=0;k<=y;k++)
a[k]=1;
a[0]=0;
a[1]=0;
for(int k=2;k<=y;k++)
{
if(a[k]==1)
{
for(j=2;k*j<=y;j++)
a[k*j]=0;
}
}
for(int k=x;k<=y;k++)
{
if(a[k]==1)
cout<<k;
}
delete []a;
i++;
}
return 0;
}
please help me resolve the problem by telling me what i need to change in my code so i don't get a sigsegv and sigabrt error.
Change:
long long int *a=new long long int[y];
to:
std::vector<bool> a=std::vector<bool>(y);
std::vector<bool> will allocate 1 bit for each 0/1 value, instead of the 64 bits that you are probably allocating for each.
It looks like you're using something similar to the Sieve of Eratosthenes. The algorithm looks like:
bool composite[N] := {false, ..., false}
composite[0] := true
composite[1] := true
for (i from 2 to N)
if (not composite[i])
for (j = 2i to N skipping by i)
composite[j] := true
For ranges like [1, 10^9], a nice option to cut memory usage is to use bit masking instead of booleans. This way, you use ~128MB instead of ~1GB of memory for the sieve. Edit: I forgot to mention that std::vector<bool> is actually internally a std::bitset, so you don't actually have to do any explicit bit twiddling.
A better option in terms of memory is to use the fact that a number is composite iff it has a non-trivial factor less than or equal to its square root, and combine that with a sieve. Of course, you have to augment the sieve with a list of primes. It will be empty initially, and you must append a prime each time you find one.
Sieve all of the primes up to 32,000 (A little more than the square root of 1,000,000,000). The result is a sorted sequence of prime numbers.
For each integer k, iterate over the primes less than or equal to the square root of k. If it's divisible by one of them, it's not prime. Otherwise, if the loop terminates, it's prime. When k < 32,000, you can avoid this entirely and just use the flag set in the sieve array.
This gives you O(sqrt(N) log log sqrt(N)) complexity for the sieve, and checking if an integer k is prime takes time O(sqrt(k) / log sqrt(k)) by the Prime Number Theorem.

How is this code working for finding the number of divisors of a number?

http://www.spoj.com/problems/NDIV/
This is the problem statement. Since i'm new to programming, this particular problem ripped me off, I found this particular code on the internet which when I tried submitting got AC. I want to know how this code worked, as I have submitted it from online source which itself is bad idea for beginners.
#include <bits/stdc++.h>
using namespace std;
int check[32000];
int prime[10000];
void shieve()
{
for(int i=3;i<=180;i+=2)
{
if(!check[i])
{
for(int j=i*i;j<=32000;j+=i)
check[j]=1;
}
}
prime[0] = 2;
int j=1;
for(int i=3;i<=32000;i+=2)
{
if(!check[i]){
prime[j++]=i;
}
}
}
int main()
{
shieve();
int a,b,n,temp,total=1,res=0;
scanf("%d%d%d",&a,&b,&n);
int count=0,i,j,k;
for(i=a;i<=b;i++)
{
temp=i;
total=1;
k=0;
for(j=prime[k];j*j<=temp;j=prime[++k])
{
count=0;
while(temp%j==0)
{
count++;
temp/=j;
}
total *=count+1;
}
if(temp!=1)
total*=2;
if(total==n)
res++;
}
printf("%d\n",res);
return 0;
}
It looks like the code works on the sieve of eratosthenes, but a few things i'm unable to understand.
Why the limit of array "check" is 32000?
Again why the limit for array prime is 10000?
Inside main, whatever is happening inside the for loop of j.
Too many confusions regarding this approach, can someone explain the whole algorithm how it's working.
The hard limit on the arrays is set probably because the problem demands so? If not then just bad code.
Inside the inner loop, you are calculating the largest power of a prime that divides the number. Why? See point 3.
The number of factors of a number n can be calculated as follows:
Let n = (p1)^(n1) * (p2)^(n2) ... where p1, p2 are primes and n1, n2 ... are their exponents. Then the number of factors of n = (n1 + 1)*(n2 + 1)...
Hence the line total *= count + 1 which is basically total = total * (count + 1) (where count is the largest exponent of the prime number that divides the original number) calculates the number of prime factors of the number.
And yes, the code implements sieve of Eratosthenes for storing primes in a table.
(Edit Just saw the problem - you need at least 10^4 boolean values to store the primes (you don't actually need to store the values, just a flag indicating whether the values are prime or not). The condition given is 0 <= b - a <= 10^4 , So start your loop from a to b and check for the bool values stored in the array to know if they are prime or not.)

Wrong result for code doing dynamic programming in C++

I am solving a dp problem .The problem is that I have N dices; each of them has K faces numbered from 1 to K. Now I have arranged the N dices in a line. I can rotate/flip any dice if I want. How many ways I can set the top faces such that the summation of all the top faces equals S?
Now I am given N, K, S; I have to calculate the total number of ways.It is worthy of mention I have to print the result modulo 100000007.I have tried to solve this problem and write a code for this one but my code doesn't work for this case:800 800 10000 why? I can't understand .Can anyone explain the cause for which my code doesn't work. My code is here:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<memory.h>
#define M 100000007
#define ull unsigned long long
using namespace std;
ull n,K,s,dp[1001][1001];
ull fnc(int num,int sum,int k)
{
ull temp;
if(num==0){
if(sum==0) return 1;
else return 0;
}
if(dp[num][k]!=-1)
return dp[num][k];
for(int i=1;i<=K;i++)
{
temp=temp%M+fnc(num-1,sum-i,i)%M;
}
return dp[num][k]=temp%M;
}
int main()
{
int T;
cin>>T;
for(int t=1;t<=T;t++)
{
cin>>n>>K>>s;
memset(dp,-1,sizeof(dp));
printf("Case %d: %lld\n",t,fnc(n,s,0));
}
return 0;
}
You used the wrong subscripts for dp.
Consider how many ways you can get 800 dice, each with numbers from 1 to 800,
to have the sum 10000 if you make the number 1 uppermost on the first die
and you make 4 uppermost on the second die.
Now consider how many ways to have the sum 10000 if you make 2 uppermost on the first die
and 3 uppermost on the second die.
Those two quantities are the same: each is the number of ways to get 798 dice (with numbers 1 to 800) to have the sum 99995. That is the kind of quantity you want to memoize.
But you have not even allocated enough space in dp to store this kind of partial answer.
I also have to wonder why you are using unsigned long long rather than just unsigned long, since your answer is to be given modulo 100000007. You should never have to
work with numbers that are even near the maximum value of a signed long.
According to http://linux.die.net/man/3/memset :
The memset() function fills the first n bytes of the memory area pointed to by s with the constant byte c.
Note it doesn't say "the constant unsigned long long c".
You have the value k and K defined in the same scope, which is infuriating.
You hard coded 1001 and -1 instead of giving them proper soft coded variable names.
Most of your variable names are 1 character long.
You have persistent behavior in a return statement.
You have absolutely nothing checking if the values of k, K, and num are within the proper range of dp, which is partially a consequence of hard coding 1001.
Spacebar is your friend, writingcodelikethisthatwehavetoreadisannoying.

Best program for Permutation nPr of large numbers

I am new to programming and was stuck at the permutation part. I have code which works for combination of large numbers which is stored in matrix but i am not able to find what should i change in that to get the result.
I tried the recursive method for permutations but could not achieve fast results.
This is the code which i got for combination what should be the change in condition which i should do here to get permutations?
void combination()
{
int i,j;
for(i=0;i<100;i++)
{
nCr[i][0]=1;
nCr[i][i]=1;
}
for(i=1;i<100;i++)
for(j=1;j<100;j++)
if (i!=j)
{
nCr[i][j] = (nCr[i-1][j] + nCr[i-1][j-1]);
}
}
A recurrence rule for permutations can be easily derived from the definition:
nPk = n*(n-1)*(n-2)* ... * (n-k+1) = n * (n-1)P(k-1)
Converted to code:
for(i=0;i<100;i++)
{
nPr[i][0]=1;
}
for(i=1;i<100;i++)
for(j=1;j<100;j++)
if (i!=j)
{
nPr[i][j] = i * nPr[i-1][j-1];
}
Note that the number of permutations grows fast and overflows the storage available for int: 13P11 for example is already out of range with signed 32bit integers.
well you can use the following pseudo-code for computing permutation and combination given that mod is always a very large prime number.
for permutation nPr
func permutation(r,n,mod):
q=factorial(n) // you should precompute them and saved in an array for a better execution time
r=(factorial(r))%mod
return (q*math.pow(r,mod-2))%mod
for combination nCr
func combination(r,n,mod):
q=factorial(n)
r=(factorial(r)*factorial(n-r))%mod
return (q*math.pow(r,mod-2))%mod
your should precompute factorials , for a decent execution time.
fact[100000]
fact[0]=fact[1]=1
func factorial_compute():
for x from 2 to 100000:
fact[x]=(x*fact[x-1])%mod
hence your factorial function will be
func factorial(x):
return(fact[x])
for reference on mathematics for this : http://mathworld.wolfram.com/ModularInverse.html
Actually, I know where the problem raised
At the point where we multiply , there is the actual problem ,when numbers get multiplied and get bigger and bigger.
this code is tested and is giving the correct result.
#include <bits/stdc++.h>
using namespace std;
#define mod 72057594037927936 // 2^56 (17 digits)
// #define mod 18446744073709551616 // 2^64 (20 digits) Not supported
long long int prod_uint64(long long int x, long long int y)
{
return x * y % mod;
}
int main()
{
long long int n=14, s = 1;
while (n != 1)
{
s = prod_uint64(s , n) ;
n--;
}
}