Wrong result for code doing dynamic programming in C++ - 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.

Related

Insert values from long variable into array and read values

I'm working on a program that takes a long variable (x) and stores it into an array, then is able to read the separate values both reversed and in order. I've used a while loop in order to store the values but am a little stuck getting the program to read the values, but practices like this will help my understanding of the subject in the long run. Any advise on where I'm making a mistake would be great, thanks in advance! I'm still kind of a n00b with arrays in C++
int arr[]={};
long x;
int i=0;
int j;
cout<<"Enter value to be stored: "<<endl;
cin>>x;
while(x>0){
int lastdigit=x%10;
arr[i]=lastdigit;
x=x/10;
}
if(arr[i]>0){
for(j=i-1;j>-1;j--){
cout<<"Array values "<<arr[j];
}
}
}
This is just to read the array values in order, I'll add the reversal once I get this part down.
Your fundamental error is here
int arr[] = {};
this creates a zero size array if it was allowed but on my machine its not even valid syntax
cannot allocate an array of constant size 0 ConsoleApplication1 C:\work\ConsoleApplication1\ConsoleApplication1.cpp 12
I changed it to
int arr[12] = {};
since 10 decimal digits is enough for a 32 bit integer, plus one to be sure, and another one just in case :-)
Next mistake is you never increment i in the mod / divide loop
Then finally you test arr[i] > 0. This is not needed, take it out
Now your code works fine
PS. Make arr a std::vector<int> so it will grow rather than hard coding to 12 digits

Greedy algorithm exercise not working properly

I'm in high school and having a test soon, one of the topics being the Greedy algorithm. I'm having an unknown issue with this exercise: "It is given an array of N integers. Using the Greedy algorithm, determine the largest number that can be written as a multiplication of two of the array elements" (Sorry if it's a bit unclear, I'm not a native English speaker).
Now, what I had in mind to solve this exercise is this: Find the largest two numbers and the lowest two numbers (in case they are both negative) and display either the multiplication of the two largest or of the two lowest, depending on which number is larger.
This is what I wrote:
#include <iostream>
using namespace std;
int a[100001],n;
int main()
{
int max1=-1000001,max2=-1000001,min1=1000001,min2=1000001,x;
cin>>n;
for (int i=1; i<=n; i++)
{
cin>>a[i];
if (a[i]>=max2)
{
if (a[i]>=max1)
{
x=max1;
max1=a[i];
max2=x;
}
else max2=a[i];
}
if (a[i]<=min2)
{
if (a[i]<=min1)
{
x=min1;
min1=a[i];
min2=x;
}
else min2=a[i];
}
}
if (n==1)
cout<<n;
else if (max1*max2>=min1*min2)
cout<<max1*max2;
else cout<<min1*min2;
return 0;
}
Yes, I know the way I wrote it is untidy/ugly. The code, however, should function properly and I tested it with both the example provided by the exercise and lots of different situations. They all gave the right result. The problem is that the programming exercises website gives my code a 80/100 score, not because of the time but because of the wrong answers.
I've already spent more than 2 hours looking at this code and I just can't figure out what's wrong with it. Can anyone point out the flaw? Thanks <3
The problem most likely comes from the fact that multiplying 2 int's will give you an int. An int usually has a range of -2,147,483,648 to 2,147,483,647.
If you then multiply 2,147,483,647 * 2 for example you get -2. Similarly taking 2,147,483,647 + 1 will give you -2147483648. When the value reaches it's max it deals with that by going to the lowest possible value.
To partially solve the problem you just need to cast 1 of the variables you multiply to a 64-bit integer. For modern C++ that would be int64_t.
if (n==1)
cout<<n;
else if (static_cast<int64_t>(max1)*max2>=static_cast<int64_t>(min1)*min2)
cout<<static_cast<int64_t>(max1)*max2;
else cout<<static_cast<int64_t>(min1)*min2;
But you will still be able to get too big number if both the values are big enough. So you need the full range of a uint64_t, the unsigned version.
So we need to cast to a uint64_t instead, but then you run into another issue with the numbers below 0. So first you should convert you min1 and min2 to the equivalent positive numbers, then cast to uint64_t.
uint64_t positive_min1, positive_min2;
if (min1 < 0 && min2 < 0) {
positive_min1 = min1*-1;
positive_min2 = min2*-1;
}
else {
positive_min1 = 0;
positive_min2 = 0;
}
Now you can go ahead and do
if (n==1)
cout<<n;
else if (static_cast<uint64_t>(max1)*max2>=positive_min1*positive_min2)
cout<<static_cast<int64_t>(max1)*max2;
else cout<<positive_min1*positive_min2;
No need to cast positive_min1 & 2 since it was already converted to uint64_t.
Since you are casting max1 to unsigned, you should probably check that it's not below 0 first.
If signed and unsigned is not familiar concepts you can read about that and the different data types here.

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.

Need a way to make this code run faster

I'm trying to solve Project Euler problem 401. They only way I could find a way to solve it was brute-force. I've been running this code for like 10 mins without any answer. Can anyone help me with ideas improve it.
Code:
#include <iostream>
#include <cmath>
#define ull unsigned long long
using namespace std;
ull sigma2(ull n);
ull SIGMA2(ull n);
int main()
{
ull ans = SIGMA2(1000000000000000) % 1000000000;
cout << "Answer: " << ans << endl;
cin.get();
cin.ignore();
return 0;
}
ull sigma2(ull n)
{
ull sum = 0;
for(ull i = 1; i<=floor(sqrt(n)); i++)
{
if(n%i == 0)
{
sum += (i*i)+((n/i)*(n/i));
}
if(i*i == n)
{
sum -= n;
}
}
return sum;
}
ull SIGMA2(ull n)
{
ull sum = 0;
for(ull i = 1; i<=n; i++)
{
sum+=sigma2(i);
}
return sum;
}
You're missing some dividers, if a/b=c, and b is a divider of a then c will also be a divider of a but cmight be greater than floor(sqrt(a)), for example 3 > floor(sqrt(6)) but divides 6.
Then you should put your floor(sqrt(n)) in a variable and use the variable in the for, otherwise you recalculate it a every operation which is very expensive.
You can do some straightforward optimizations:
inline sigma2,
calculate floor(sqrt(n)) before the loop (but compiler may be doing it anyway, though),
precalculate squares of all ints from 1 to n and then use array lookup instead of multiplication
You will gain more by changing your approach. Think what you are trying to do - summing squares of all divisors of all integers from 1 to n. You grouped divisors by what they divide, but you can regroup terms in this sum. Let's group divisors by their value:
1 divides everything so it will appear n times in the sum, bringing 1*1*n total,
2 divides evens and will appear n/2 (integer division!) times, bringing 2*2*(n/2) total,
k ... will bring k*k*(n/k) total.
So we should just add up k*k*(n/k) for k from 1 to n.
Think about the problem.
Bruteforce the way you tried is obviously not a good idea.
You should come up with something better...
Isn't there any method how to use some nice prime factorization method to speed up the computation? Isn't there any recursion pattern? Try to find something...
One simple optimization that you can carry out is that there will be many repeated factors in the numbers.
So first estimate in how many numbers would 1 be a factor ( all N numbers ).
In how many numbers would 2 be a factor ( N/2 ).
...
Similarly for others.
Just multiply their squares with their frequency.
Time complexity shall then straight-away reduce to O(N)
There are obvious microoptimizations such as ++i rather than i++ or getting floor(sqrt(n)) out of the loop (these are two floating point operations which are really expensive compared to other integer operation in the loop), and calculting n/i only once (use a dummy variable for it and then calculate the square of the dummy).
There are also rather obvious simplifications in the algorithm. For example SIGMA2(i) = SIGMA2(i-1) + sigma2(i). But do not use recursion since you need a really huge number, this would not work and your stack memory would be exhausted. Use loop instead of recursion. There is a huge potential for improvement.
And well, there is a bigger problem - 10^15 has 15 digits. This number squared has 30 digits. There is no way you can store this into unsigned long long, which has I think about 20 digits. So you need to employ somehow the modulo 10^9 (the end of the assignment) and get additional space for your calculations...
And when using brute force, print out the temporary result every milion number for example to give you idea how fast you are approaching to the final result. Waiting 10 minutes blindly is not a good idea.

SPOJ Problem KPRIMES2

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.