Related
I have removed all the storylines for this question.
Q. You are given N numbers. You have to find 2 equal sum sub-sequences, with maximum sum. You don't necessarily need to use all numbers.
Eg 1:-
5
1 2 3 4 1
Sub-sequence 1 : 2 3 // sum = 5
Sub-sequence 2 : 4 1 // sum = 5
Possible Sub-sequences with equal sum are
{1,2} {3} // sum = 3
{1,3} {4} // sum = 4
{2,3} {4,1} // sum = 5
Out of which 5 is the maximum sum.
Eg 2:-
6
1 2 4 5 9 1
Sub-sequence 1 : 2 4 5 // sum = 11
Sub-sequence 2 : 1 9 1 // sum = 11
The maximum sum you can get is 11
Constraints:
5 <= N <= 50
1<= number <=1000
sum of all numbers is <= 1000
Important: Only <iostream> can be used. No STLs.
N numbers are unsorted.
If array is not possible to split, print 0.
Number of function stacks is limited. ie your recursive/memoization solution won't work.
Approach 1:
I tried a recursive approach something like the below:
#include <iostream>
using namespace std;
bool visited[51][1001][1001];
int arr[51];
int max_height=0;
int max_height_idx=0;
int N;
void recurse( int idx, int sum_left, int sum_right){
if(sum_left == sum_right){
if(sum_left > max_height){
max_height = sum_left;
max_height_idx = idx;
}
}
if(idx>N-1)return ;
if(visited[idx][sum_left][sum_right]) return ;
recurse( idx+1, sum_left+arr[idx], sum_right);
recurse( idx+1, sum_left , sum_right+arr[idx]);
recurse( idx+1, sum_left , sum_right);
visited[idx][sum_left][sum_right]=true;
/*
We could reduce the function calls, by check the visited condition before calling the function.
This could reduce stack allocations for function calls. For simplicity I have not checking those conditions before function calls.
Anyways, this recursive solution would get time out. No matter how you optimize it.
Btw, there are T testcases. For simplicity, removed that constraint.
*/
}
int main(){
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cin>>N;
for(int i=0; i<N; i++)
cin>>arr[i];
recurse(0,0,0);
cout<< max_height <<"\n";
}
NOTE: Passes test-cases. But time out.
Approach 2:
I also tried, taking advantage of constraints.
Every number has 3 possible choice:
1. Be in sub-sequence 1
2. Be in sub-sequence 2
3. Be in neither of these sub-sequences
So
1. Be in sub-sequence 1 -> sum + 1*number
2. Be in sub-sequence 2 -> sum + -1*number
3. None -> sum
Maximum sum is in range -1000 to 1000.
So dp[51][2002] could be used to save the maximum positive sum achieved so far (ie till idx).
CODE:
#include <iostream>
using namespace std;
int arr[51];
int N;
int dp[51][2002];
int max3(int a, int b, int c){
return max(a,max(b,c));
}
int max4(int a, int b, int c, int d){
return max(max(a,b),max(c,d));
}
int recurse( int idx, int sum){
if(sum==0){
// should i perform anything here?
}
if(idx>N-1){
return 0;
}
if( dp[idx][sum+1000] ){
return dp[idx][sum+1000];
}
return dp[idx][sum+1000] = max3 (
arr[idx] + recurse( idx+1, sum + arr[idx]),
0 + recurse( idx+1, sum - arr[idx]),
0 + recurse( idx+1, sum )
) ;
/*
This gives me a wrong output.
4
1 3 5 4
*/
}
int main(){
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cin>>N;
for(int i=0; i<N; i++)
cin>>arr[i];
cout<< recurse(0,0) <<"\n";
}
The above code gives me wrong answer. Kindly help me with solving/correcting this memoization.
Also open to iterative approach for the same.
Idea of your second approach is correct, it's basically a reduction to the knapsack problem. However, it looks like your code lacks clear contract: what the recurse function is supposed to do.
Here is my suggestion: int recurse(int idx, int sum) distributes elements on positions idx..n-1 into three multisets A, B, C such that sum+sum(A)-sum(B)=0 and returns maximal possible sum(A), -inf otherwise (here -inf is some hardcoded constant which serves as a "marker" of no answer; there are some restrictions on it, I suggest -inf == -1000).
Now you're to write a recursive backtracking using that contract and then add memoization. Voila—you've got a dynamic programming solution.
In recursive backtracking we have two distinct situations:
There are no more elements to distribute, no choices to make: idx == n. In that case, we should check that our condition holds (sum + sum(A) - sum(B) == 0, i.e. sum == 0) and return the answer. If sum == 0, then the answer is 0. However, if sum != 0, then there is no answer and we should return something which will never be chosen as the answer, unless there are no answer for the whole problem. As we modify returning value of recurse and do not want extra ifs, it cannot be simply zero or even -1; it should be a number which, when modified, still remains "the worst answer ever". The biggest modification we can make is to add all numbers to the resulting value, hence we should choose something less or equal to negative maximal sum of numbers (i.e. -1000), as existing answers are always strictly positive, and that fictive answer will always be non-positive.
There is at least one remaining element which should be distributed to either A, B or C. Make the choice and choose the best answer among three options. Answers are calculated recursively.
Here is my implementation:
const int MAXN = 50;
const int MAXSUM = 1000;
bool visited[MAXN + 1][2 * MAXSUM + 1]; // should be filled with false
int dp[MAXN + 1][2 * MAXSUM + 1]; // initial values do not matter
int recurse(int idx, int sum){
// Memoization.
if (visited[idx][sum + MAXSUM]) {
return dp[idx][sum + MAXSUM];
}
// Mark the current state as visited in the beginning,
// it's ok to do before actually computing it as we're
// not expect to visit it while computing.
visited[idx][sum + MAXSUM] = true;
int &answer = dp[idx][sum + MAXSUM];
// Backtracking search follows.
answer = -MAXSUM; // "Answer does not exist" marker.
if (idx == N) {
// No more choices to make.
if (sum == 0) {
answer = 0; // Answer exists.
} else {
// Do nothing, there is no answer.
}
} else {
// Option 1. Current elemnt goes to A.
answer = max(answer, arr[idx] + recurse(idx + 1, sum + arr[idx]));
// Option 2. Current element goes to B.
answer = max(answer, recurse(idx + 1, sum - arr[idx]));
// Option 3. Current element goes to C.
answer = max(answer, recurse(idx + 1, sum));
}
return answer;
}
Here is a simple dynamic programming based solution for anyone interested, based on the idea suggested by Codeforces user lemelisk here. Complete post here. I haven't tested this code completely though.
#include <iostream>
using namespace std;
#define MAXN 20 // maximum length of array
#define MAXSUM 500 // maximum sum of all elements in array
#define DIFFSIZE (2*MAXSUM + 9) // possible size of differences array (-maxsum, maxsum) + some extra
int dp[MAXN][DIFFSIZE] = { 0 };
int visited[DIFFSIZE] = { 0 }; // visited[diff] == 1 if the difference 'diff' can be reached
int offset = MAXSUM + 1; // offset so that indices in dp table don't become negative
// 'diff' replaced by 'offset + diff' below everywhere
int max(int a, int b) {
return (a > b) ? a : b;
}
int max_3(int a, int b, int c) {
return max(a, max(b, c));
}
int main() {
int a[] = { 1, 2, 3, 4, 6, 7, 5};
int n = sizeof(a) / sizeof(a[0]);
int *arr = new int[n + 1];
int sum = 0;
for (int i = 1; i <= n; i++) {
arr[i] = a[i - 1]; // 'arr' same as 'a' but with 1-indexing for simplicity
sum += arr[i];
} // 'sum' holds sum of all elements of array
for (int i = 0; i < MAXN; i++) {
for (int j = 0; j < DIFFSIZE; j++)
dp[i][j] = INT_MIN;
}
/*
dp[i][j] signifies the maximum value X that can be reached till index 'i' in array such that diff between the two sets is 'j'
In other words, the highest sum subsets reached till index 'i' have the sums {X , X + diff}
See http://codeforces.com/blog/entry/54259 for details
*/
// 1 ... i : (X, X + diff) can be reached by 1 ... i-1 : (X - a[i], X + diff)
dp[0][offset] = 0; // subset sum is 0 for null set, difference = 0 between subsets
visited[offset] = 1; // initially zero diff reached
for (int i = 1; i <= n; i++) {
for (int diff = (-1)*sum; diff <= sum; diff++) {
if (visited[offset + diff + arr[i]] || visited[offset + diff - arr[i]] || visited[offset + diff]) {
// if difference 'diff' is reachable, then only update, else no need
dp[i][offset + diff] = max_3
(
dp[i - 1][offset + diff],
dp[i - 1][offset + diff + arr[i]] + arr[i],
dp[i - 1][offset + diff - arr[i]]
);
visited[offset + diff] = 1;
}
}
/*
dp[i][diff] = max {
dp[i - 1][diff] : not taking a[i] in either subset
dp[i - 1][diff + arr[i]] + arr[i] : putting arr[i] in first set, thus reducing difference to 'diff', increasing X to X + arr[i]
dp[i - 1][diff - arr[i]] : putting arr[i] in second set
initialization: dp[0][0] = 0
*/
// O(N*SUM) algorithm
}
cout << dp[n][offset] << "\n";
return 0;
}
Output:
14
State is not updated in Approach 1. Change the last line of recurse
visited[idx][sum_left][sum_right];
to
visited[idx][sum_left][sum_right] = 1;
Also memset the visited array to false before calling recurse from main.
I have to create a minimal prime generator in C (we need the minimal primes that have at least two digits) and i cannot use tables.So my thought was first find all the primes,second with using masks to find all the subsequences of each number and finally check if every subsequence is not a prime number.i cannot find the minimal primes because i didnt put a condition to check if a subsequence is prime or no?(my code is not ready so it may have some mistakes but it runs)
my code
#include <stdio.h>
#define MAXNUMB 100
int main ()
{
int i,j,x,mask,max=1,mult,sub;
for (i = 11 ; i < MAXNUMB; i += 2 ) {
for (j = 3; j * j <= i; j += 2) {
if (i % j == 0) {
break;
}
}
if (j * j > i) {
int length = 0;
int tmp=i;
while (tmp != 0) {
tmp /= 10;
length++;
}
for (x=1;x<length*2;x++) {
mask=x;
mult=1;
sub=0;
int num=i;
while ( num != 0 ) {
if ( mask % 2 == 1 ) {
sub += num % 10 * mult;
mult *= 10;
}
num /= 10;
mask /= 2;
}
printf ("%d \n",sub);
}
printf ("%d is minimal prime \n",i);
}
}
}
If MAXNUMB is not too large then you can very quickly find all the primes until MAXNUMB using the Sieve_of_Eratosthenes. After you have that you can get every subsequence of an n-digit number by counting from 1 to 2^n-1 and use the bit-pattern of the current count to specify the current subsequence. Check each subsequence in the sieve.
If MAXNUMB is too big then you can build the sieve up to sqrt(MAXNUMB), so that when you test a number whether it's prime or not you just have to check whether it's divisible with any prime, instead of checking whether it's divisible any odd number.
Wikipedia has a nice pseudocode algorithm for primality. It's naive, but it works.
function is_prime(n : integer)
if n ≤ 1
return false
else if n ≤ 3
return true
else if n mod 2 = 0 or n mod 3 = 0
return false
let i ← 5
while i×i ≤ n
if n mod i = 0 or n mod (i + 2) = 0
return false
i ← i + 6
return true
I'll leave translating this into C for you. My one note is that i should be of a type larger than n's type. For the reason, consider what happens to i×i ≤ n when n is the largest integer.
When you're ready, you can look at my solution to this problem.
The concept of a minimal prime is moderately interesting. I wrote the following code to do the checking.
/* SO 33838621: Minimal Primes */
/*
** Find the minimal primes less than 100,000.
**
** A minimal prime is a prime number for which no subsequence of the digits
** that make up the number is itself prime.
** The question gives two examples:
** = 881 is prime and is a minimal prime because none of { 8, 8, 1, 88,
** 81, 81 } are prime.
** = 109 is prime but is not a minimal prime because { 1, 0, 9, 10, 9,
** 19 } includes the prime 19.
** Clearly, the single digit primes are all trivially minimal.
**
** Additional wrinkle: the code may not build up a table of primes.
**
** NB: All primes except 2 and 3 have the form 6N±1
*/
/*
** There are two problems to solve:
** (1) Check for primality without using a table of primes.
** (2) Generate all subsequences of a number.
** The latter problem is somewhat harder than the former.
** The surviving solution uses recursive string manipulation.
**
** NB: Command subsequences is derived from this, and helps check
** the validity of the minimal primes.
*/
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static bool is_prime(int n)
{
if (n < 2)
return false;
if (n == 2 || n == 3 || n == 5 || n == 7)
return true;
if (n % 2 == 0 || n % 3 == 0 || n % 5 == 0 || n % 7 == 0)
return false;
for (int c = 12; (c - 1) * (c - 1) <= n; c += 6)
{
if (n % (c - 1) == 0 || n % (c + 1) == 0)
return false;
}
return true;
}
static bool has_prime_n_digit_subset(int p0, int n_digits, const char *buffer, int buflen)
{
//printf("-->> p0 = %5d, n = %d (%s)\n", p0, n_digits, buffer);
assert(buflen >= 0 && strlen(buffer) == (size_t)buflen);
for (int i = 0; i < buflen; i++)
{
int p1 = 10 * p0 + buffer[i] - '0';
if (n_digits > 1)
{
if (has_prime_n_digit_subset(p1, n_digits - 1, &buffer[i+1], buflen - i - 1))
{
//printf("<<-- true\n");
return true;
}
}
else
{
//printf("C %d\n", p1);
if (is_prime(p1))
{
//printf("<<-- p1 = %d: true\n", p1);
return true;
}
}
}
//printf("<<-- false\n");
return false;
}
static void check_minimal_prime(int n)
{
assert(n > 0);
if (is_prime(n))
{
//printf("P %d\n", n);
char buffer[20];
sprintf(buffer, "%d", n);
char n_digits = strlen(buffer);
for (int i = 1; i < n_digits; i++)
{
if (has_prime_n_digit_subset(0, i, buffer, n_digits))
return;
}
printf("%d\n", n); /* It's a minimal prime */
}
}
int main(int argc, char **argv)
{
int max = 100000;
if (argc > 2)
{
fprintf(stderr, "Usage: %s [maximum]\n", argv[0]);
exit(1);
}
else if (argc == 2)
{
max = atoi(argv[1]);
if (max <= 0)
{
fprintf(stderr, "Invalid number (%d from %s)\n", max, argv[1]);
exit(1);
}
}
max /= 6;
check_minimal_prime(2);
check_minimal_prime(3);
for (int c = 1; c < max; c++)
{
check_minimal_prime(6 * c - 1);
check_minimal_prime(6 * c + 1);
}
return 0;
}
The list of numbers generated was:
2
3
5
7
11
19
41
61
89
409
449
499
881
991
6469
6949
9001
9049
9649
9949
60649
666649
946669
60000049
66000049
66600049
I didn't find any more minimal primes when checking up to 1,000,000,000. Timing was:
100 0m0.006s
1000 0m0.006s
10000 0m0.006s
100000 0m0.012s
1000000 0m0.129s
10000000 0m2.617s
100000000 1m8.200s
1000000000 32m34.561s
I am trying to write a code for calculating the number of trailing zeroes in a factorial of a specific number (large numbers). However, for small numbers, i get the correct result, but for large the deviations keeps increasing. What's wrong with my logic
#include <stdio.h>
int main(void) {
int t;
scanf("%d", &t);
while (t > 0) {
int factorten = 0, factorfive = 0, factortwo = 0, remainingfive = 0,
remainingtwo = 0;
unsigned int factors = 0;
unsigned int n;
scanf("%u", &n);
for (unsigned int i = n; i > 0; i--) {
if (i % 10 == 0) {
factorten++;
continue;
} else if (i % 5 == 0) {
factorfive++;
continue;
} else if (i % 2 == 0) {
// int new = i;
// while(new % 2 == 0)
//{
// new = new / 2;
factortwo++;
//}
continue;
}
}
factors = factors + factorten;
printf("%u\n", factors);
if (factorfive % 2 == 0 && factorfive != 0) {
factors = factors + (factorfive / 2);
} else {
remainingfive = factorfive % 2;
factors = factors + ((factorfive - remainingfive) / 2);
}
printf("%u\n", factors);
if (factortwo % 5 == 0 && factortwo != 0) {
factors = factors + (factortwo / 5);
} else {
remainingtwo = factortwo % 5;
factors = factors + ((factortwo - remainingtwo) / 5);
}
printf("%u\n", factors);
if ((remainingfive * remainingtwo % 10) == 0 &&
(remainingfive * remainingtwo % 10) != 0) {
factors++;
}
printf("%u\n", factors);
t--;
}
}
Sample Input:
6
3
60
100
1024
23456
8735373
Sample Output:
0
14
24
253
5861
2183837
My OUTPUT
0
13
23
235
5394
2009134
Edit: ignore the first two, they are suboptimal. The third algorithm is optimal.
I think this does what you're trying to do, but is a lot simpler and works:
int tzif(int n)
{
int f2 = 0, f5 = 0;
for (;n > 1; n--)
{
int x = n;
for (;x % 2 == 0; x /= 2)
f2++;
for (;x % 5 == 0; x /= 5)
f5++;
}
return f2 > f5 ? f5 : f2;
}
It counts 2-factors and 5-factors of numbers N...2. Then it returns the smaller of the two (because adding 2-factors is useless without adding 5-factors and vice-versa). Your code is too strange for me to analyze.
I think this should work too, because a factorial will have enough 2-factors to "cover" the 5-factors:
int tzif(int n)
{
int f5 = 0;
for (;n > 1; n--)
for (x = n;x % 5 == 0; x /= 5)
f5++;
return f5;
}
This only counts 5-factors and returns that.
Another method I think should work:
int tzif(int n)
{
int f5 = 0;
for (int d = 5; d <= n; d *= 5)
f5 += n / d;
return f5;
}
Count every fifth number (each has a 5-factor), then every 25-th number (each has another 5-factor), etc.
Have 3 counters - c2,c5,c10.
I think the checks should be
divisible by 5 but not by 10 -> c5++
divisible by 2 but not by 10 -> c2++
divisible by 10. Here if true, then count number of 0's. (c10++)
At last number of 0's will be
smaller_of(c2,c5) + c10
Try to code using this. Should work.
First the trailing 0 in N! are determined by factors 2 and 5 (10). The factors 2 always would be more that the factors 5 in this case you only need to calculate how factors 5 are in the N!.
(N!/5) would give you the number of multiple of 5 (5^1) in N!
(N!/25) would give you the number of multiple of 25 (5^2) in N!
(N!/125) would give you the number of multiple of 125 (5^3) in N!
...
(N!/5^n) would give you the number of multiple of 5^n in N!
When you add the multiple of 5 you are adding too the multiple of 25, 125, ..., 5^n, when you add multiple of 25 you are adding too the multiple of 125, ..., 5^n, etc...
In that case you only need to iterate the power of 5 less or equal than N and add the number of multiple of that 5 power.
Code:
long long trailing_zeros(long long N) {
long long zeros = 0;
for (long long power5 = 5; power5 <= N; power5 *= 5)
zeros += N / power5;
return zeros;
}
#include<iostream>
int main()
{
int size,i;
std::cin >> size;
int*fact;
fact = new int[size];
for (i = 0; i < size; i++)
{
std::cin >> fact[size];
}
for (i = 0; i < size; i++)
{
int con = 5;
int multiple = 0;
do
{
multiple = multiple+(fact[size] / con);
con = con * 5;
} while (con < fact[size]);
std::cout << multiple <<'\n';
}
return 0;
}
this code works perfectly for a single input..bt for multiple inputs it prints the o/p for the last entered number...what is wrong..i jst cant think off it
I'm trying to write a program in C that will solve the following cryptarithm:
one + one = two
seven is prime
nine is a perfect square
Namely, I need to find the numerical values for the words one, two, seven and nine where each letter (o, n, e, t, w, s, v, i) is assigned a numerical value and the complete number also meets all of the above conditions.
I was thinking along the lines of creating an int array for each of the words and then 1) checking if each word meets the condition (e.g is a prime for "seven") and then 2) checking if each integer in the array is consistant with the value of the other words, where the other words also are found to meet their respective conditions.
I can't really see this working though as I would have to continuously convert the int array to a single int throughout every iteration and then I'm not sure how I can simultaneously match each element in the array with the other words.
Perhaps knowing the MIN and MAX numerical range that must be true for each of the words would be useful?
Any ideas?
For a brute-force (ish) method, I'd start with the prime seven, and use the Sieve of Eratosthenes to get all the prime numbers up to 99999. You could discard all answers where the 2nd and 4th digit aren't the same. After that you could move on to the square nine, because three of the digits are determined by the prime seven. That should narrow down the possibilities nicely, and then you can just use the answer of #pmg to finish it off :-).
Update: The following C# program seems to do it
bool[] poss_for_seven = new bool[100000]; // this will hold the possibilities for `seven`
for (int seven = 0; seven < poss_for_seven.Length; seven++)
poss_for_seven[seven] = (seven > 9999); // `seven` must have 5 digits
// Sieve of Eratosthenes to make `seven` prime
for (int seven = 2; seven < poss_for_seven.Length; seven++) {
for (int j = 2 * seven; j < poss_for_seven.Length; j += seven) {
poss_for_seven[j] = false;
}
}
// look through the array poss_for_seven[], considering each possibility in turn
for (int seven = 10000; seven < poss_for_seven.Length; seven++) {
if (poss_for_seven[seven]) {
int second_digit = ((seven / 10) % 10);
int fourth_digit = ((seven / 1000) % 10);
if (second_digit == fourth_digit) {
int e = second_digit;
int n = (seven % 10); // NB: `n` can't be zero because otherwise `seven` wouldn't be prime
for (int i = 0; i < 10; i++) {
int nine = n * 1000 + i * 100 + n * 10 + e;
int poss_sqrt = (int)Math.Floor(Math.Sqrt(nine) + 0.1); // 0.1 in case of of rounding error
if (poss_sqrt * poss_sqrt == nine) {
int o = ((2 * e) % 10); // since 2 * `one` = `two`, we now know `o`
int one = o * 100 + n * 10 + e;
int two = 2 * one;
int t = ((two / 100) % 10);
int w = ((two / 10) % 10);
// turns out that `one`=236, `two`=472, `nine` = 3136.
// look for solutions where `s` != `v` with `s` and `v' different from `o`, `n`, `e`,`t`, `w` and `i`
int s = ((seven / 10000) % 10);
int v = ((seven / 100) % 10);
if (s != v && s != o && s != n && s != e && s != t && s != w && s != i && v != o && v != n && v != e && v != t && v != w && v != i) {
System.Diagnostics.Trace.WriteLine(seven + "," + nine + "," + one + "," + two);
}
}
}
}
}
}
It seems that nine is always equal to 3136, so that one = 236 and two = 472. However, there are 21 possibiliites for seven. If one adds the constraint that no two digits can take the same value (which is what the C# code above does), then it reduces to just one possibility (although a bug in my code meant this answer originally had 3 possibilities):
seven,nine,one,two
56963,3136,236,472
I just found the time to build a c program to solve your cryptarithm.
I think that tackling the problem mathematicaly, prior to starting the brute force programming, will heavily increase the speed of the output.
Some math (number theory):
Since ONE + ONE = TWO, O cant be larget than 4, because ONE + ONE would result 4 digits. Also O cant be 0. TWO end with O and is an even number, because it is 2 * ONE.
Applying these 3 filters to O, the possible values remain O= {2,4}
Hence E can be {1,2,6,7} because (E+E) modulus 10 must be = O. More specificaly, O=2 implicates E={1,6} and O=4 implicates E={2,7}
Now lets filter N. Given that SEVEN is prime, N must be an odd number. Also N cant be 5, because all that ends with 5 is divisible by 5. Hence N={1,3,7,9}
Now that we have reduced the possibilites for the most ocurring characters (O,E,N), we are ready to hit this cryptarith with all of our brutality, having iterations drastically reduced.
Heres the C code:
#include <stdio.h>
#include <math.h>
#define O 0
#define N 1
#define E 2
#define T 3
#define W 4
#define S 5
#define V 6
#define I 7
bool isPerfectSquare(int number);
bool isPrime(int number);
void printSolutions(int countSolutions);
int filterNoRepeat(int unfilteredCount);
int solutions[1000][8]; // solution holder
int possibilitiesO[2] = {2,4};
int possibilitiesN[4] = {1,3,7,9};
int possibilitiesE[4] = {1,6,2,7};
void main() {
int countSolutions = 0;
int numberOne;
// iterate to fill up the solutions array by: one + one = two
for(int o=0;o<2;o++) {
for(int n=0;n<4;n++) {
for(int e=2*o;e<2*o+2;e++) { // following code is iterated 2*4*2 = 16 times
numberOne = 100*possibilitiesO[o] + 10*possibilitiesN[n] + possibilitiesE[e];
int w = ((2*numberOne)/10)%10;
int t = ((2*numberOne)/100)%10;
// check if NINE is a perfect square
for(int i=0;i<=9;i++) { // i can be anything ----- 10 iterations
int numberNine = 1000*possibilitiesN[n] + 100*i + 10*possibilitiesN[n] + possibilitiesE[e];
if(isPerfectSquare(numberNine)) {
// check if SEVEN is prime
for(int s=1;s<=9;s++) { // s cant be 0 ------ 9 iterations
for(int v=0;v<=9;v++) { // v can be anything other than s ------- 10 iterations
if(v==s) continue;
int numberSeven = 10000*s + 1000*possibilitiesE[e] + 100*v + 10*possibilitiesE[e] + possibilitiesN[n];
if(isPrime(numberSeven)) { // store solution
solutions[countSolutions][O] = possibilitiesO[o];
solutions[countSolutions][N] = possibilitiesN[n];
solutions[countSolutions][E] = possibilitiesE[e];
solutions[countSolutions][T] = t;
solutions[countSolutions][W] = w;
solutions[countSolutions][S] = s;
solutions[countSolutions][V] = v;
solutions[countSolutions][I] = i;
countSolutions++;
}
}
}
}
}
}
}
}
// 16 * 9 * 10 * 10 = 14400 iterations in the WORST scenario, conditions introduced reduce MOST of these iterations to 1 if() line
// iterations consumed by isPrime() function are not taken in count in the aproximation above.
// filter solutions so that no two letter have the same digit
countSolutions = filterNoRepeat(countSolutions);
printSolutions(countSolutions); // voila!
}
bool isPerfectSquare(int number) { // check if given number is a perfect square
double root = sqrt((double)number);
if(root==floor(root)) return true;
else return false;
}
bool isPrime(int number) { // simple algoritm to determine if given number is prime, check interval from sqrt(number) to number/2 with a step of +2
int startValue = sqrt((double)number);
if(startValue%2==0) startValue--; // make it odd
for(int k=startValue;k<number/2;k+=2) {
if(number%k==0) return false;
}
return true;
}
void printSolutions(int countSolutions) {
for(int k=0;k<countSolutions;k++) {
int one = 100*solutions[k][O] + 10*solutions[k][N] + solutions[k][E];
int two = 100*solutions[k][T] + 10*solutions[k][W] + solutions[k][O];
int seven = 10000*solutions[k][S] + 1000*solutions[k][E] + 100*solutions[k][V] + 10*solutions[k][E] + solutions[k][N];
int nine = 1000*solutions[k][N] + 100*solutions[k][I] + 10*solutions[k][N] + solutions[k][E];
printf("ONE: %d, TWO: %d, SEVEN: %d, NINE %d\n",one,two,seven,nine);
}
}
int filterNoRepeat(int unfilteredCount) {
int nrSol = 0;
for(int k=0;k<unfilteredCount;k++) {
bool isValid = true;
for(int i=0;i<7;i++) { // if two letters match, solution is not valid
for(int j=i+1;j<8;j++) {
if(solutions[k][i]==solutions[k][j]) {
isValid = false;
break;
}
}
if(!isValid) break;
}
if(isValid) { // store solution
for(int i=0;i<8;i++) {
solutions[nrSol][i] = solutions[k][i];
}
nrSol++;
}
}
return nrSol;
}
You can try the code yourself if you are still interested in this :P. The result is one single solution: ONE: 236, TWO: 472, SEVEN: 56963, NINE: 3136
This solution is the same as Stochastically's solutions, confirming the correctness of both algorithms i think :).
Thanks for providing this nice cryptarithm and have a nice day!
Brute force FTW!
#define ONE ((o*100) + (n*10) + e)
#define TWO ((t*100) + (w*10) + o)
#define SEVEN ((s*10000) + (e*1010) + (v*100) + n)
#define NINE ((n*1010) + (i*100) + e)
for (o = 1; o < 10; o++) { /* 1st digit cannot be zero (one) */
for (n = 1; n < 10; n++) { /* 1st digit cannot be zero (nine) */
if (n == o) continue;
for (e = 0; n < 10; n++) {
if (e == n) continue;
if (e == o) continue;
/* ... */
if (ONE + ONE == TWO) /* whatever */;
/* ... */
}
}
}
I am trying to solve an online judge problem: http://opc.iarcs.org.in/index.php/problems/LEAFEAT
The problem in short:
If we are given an integer L and a set of N integers s1,s2,s3..sN, we have to find how many numbers there are from 0 to L-1 which are not divisible by any of the 'si's.
For example, if we are given, L = 20 and S = {3,2,5} then there are 6 numbers from 0 to 19 which are not divisible by 3,2 or 5.
L <= 1000000000 and N <= 20.
I used the Inclusion-Exclusion principle to solve this problem:
/*Let 'T' be the number of integers that are divisible by any of the 'si's in the
given range*/
for i in range 1 to N
for all subsets A of length i
if i is odd then:
T += 1 + (L-1)/lcm(all the elements of A)
else
T -= 1 + (L-1)/lcm(all the elements of A)
return T
Here is my code to solve this problem
#include <stdio.h>
int N;
long long int L;
int C[30];
typedef struct{int i, key;}subset_e;
subset_e A[30];
int k;
int gcd(a,b){
int t;
while(b != 0){
t = a%b;
a = b;
b = t;
}
return a;
}
long long int lcm(int a, int b){
return (a*b)/gcd(a,b);
}
long long int getlcm(int n){
if(n == 1){
return A[0].key;
}
int i;
long long int rlcm = lcm(A[0].key,A[1].key);
for(i = 2;i < n; i++){
rlcm = lcm(rlcm,A[i].key);
}
return rlcm;
}
int next_subset(int n){
if(k == n-1 && A[k].i == N-1){
if(k == 0){
return 0;
}
k--;
}
while(k < n-1 && A[k].i == A[k+1].i-1){
if(k <= 0){
return 0;
}
k--;
}
A[k].key = C[A[k].i+1];
A[k].i++;
return 1;
}
int main(){
int i,j,add;
long long int sum = 0,g,temp;
scanf("%lld%d",&L,&N);
for(i = 0;i < N; i++){
scanf("%d",&C[i]);
}
for(i = 1; i <= N; i++){
add = i%2;
for(j = 0;j < i; j++){
A[j].key = C[j];
A[j].i = j;
}
temp = getlcm(i);
g = 1 + (L-1)/temp;
if(add){
sum += g;
} else {
sum -= g;
}
k = i-1;
while(next_subset(i)){
temp = getlcm(i);
g = 1 + (L-1)/temp;
if(add){
sum += g;
} else {
sum -= g;
}
}
}
printf("%lld",L-sum);
return 0;
}
The next_subset(n) generates the next subset of size n in the array A, if there is no subset it returns 0 otherwise it returns 1. It is based on the algorithm described by the accepted answer in this stackoverflow question.
The lcm(a,b) function returns the lcm of a and b.
The get_lcm(n) function returns the lcm of all the elements in A.
It uses the property : LCM(a,b,c) = LCM(LCM(a,b),c)
When I submit the problem on the judge it gives my a 'Time Limit Exceeded'. If we solve this using brute force we get only 50% of the marks.
As there can be upto 2^20 subsets my algorithm might be slow, hence I need a better algorithm to solve this problem.
EDIT:
After editing my code and changing the function to the Euclidean algorithm, I am getting a wrong answer, but my code runs within the time limit. It gives me a correct answer to the example test but not to any other test cases; here is a link to ideone where I ran my code, the first output is correct but the second is not.
Is my approach to this problem correct? If it is then I have made a mistake in my code, and I'll find it; otherwise can anyone please explain what is wrong?
You could also try changing your lcm function to use the Euclidean algorithm.
int gcd(int a, int b) {
int t;
while (b != 0) {
t = b;
b = a % t;
a = t;
}
return a;
}
int lcm(int a, int b) {
return (a * b) / gcd(a, b);
}
At least with Python, the speed differences between the two are pretty large:
>>> %timeit lcm1(103, 2013)
100000 loops, best of 3: 9.21 us per loop
>>> %timeit lcm2(103, 2013)
1000000 loops, best of 3: 1.02 us per loop
Typically, the lowest common multiple of a subset of k of the s_i will exceed L for k much smaller than 20. So you need to stop early.
Probably, just inserting
if (temp >= L) {
break;
}
after
while(next_subset(i)){
temp = getlcm(i);
will be sufficient.
Also, shortcut if there are any 1s among the s_i, all numbers are divisible by 1.
I think the following will be faster:
unsigned gcd(unsigned a, unsigned b) {
unsigned r;
while(b) {
r = a%b;
a = b;
b = r;
}
return a;
}
unsigned recur(unsigned *arr, unsigned len, unsigned idx, unsigned cumul, unsigned bound) {
if (idx >= len || bound == 0) {
return bound;
}
unsigned i, g, s = arr[idx], result;
g = s/gcd(cumul,s);
result = bound/g;
for(i = idx+1; i < len; ++i) {
result -= recur(arr, len, i, cumul*g, bound/g);
}
return result;
}
unsigned inex(unsigned *arr, unsigned len, unsigned bound) {
unsigned i, result = bound, t;
for(i = 0; i < len; ++i) {
result -= recur(arr, len, i, 1, bound);
}
return result;
}
call it with
unsigned S[N] = {...};
inex(S, N, L-1);
You need not add the 1 for the 0 anywhere, since 0 is divisible by all numbers, compute the count of numbers 1 <= k < L which are not divisible by any s_i.
Create an array of flags with L entries. Then mark each touched leaf:
for(each size in list of sizes) {
length = 0;
while(length < L) {
array[length] = TOUCHED;
length += size;
}
}
Then find the untouched leaves:
for(length = 0; length < L; length++) {
if(array[length] != TOUCHED) { /* Untouched leaf! */ }
}
Note that there is no multiplication and no division involved; but you will need up to about 1 GiB of RAM. If RAM is a problem the you can use an array of bits (max. 120 MiB).
This is only a beginning though, as there are repeating patterns that can be copied instead of generated. The first pattern is from 0 to S1*S2, the next is from 0 to S1*S2*S3, the next is from 0 to S1*S2*S3*S4, etc.
Basically, you can set all values touched by S1 and then S2 from 0 to S1*S2; then copy the pattern from 0 to S1*S2 until you get to S1*S2*S3 and set all the S3's between S3 and S1*S2*S3; then copy that pattern until you get to S1*S2*S3*S4 and set all the S4's between S4 and S1*S2*S3*S4 and so on.
Next; if S1*S2*...Sn is smaller than L, you know the pattern will repeat and can generate the results for lengths from S1*S2*...Sn to L from the pattern. In this case the size of the array only needs to be S1*S2*...Sn and doesn't need to be L.
Finally, if S1*S2*...Sn is larger than L; then you could generate the pattern for S1*S2*...(Sn-1) and use that pattern to create the results from S1*S2*...(Sn-1) to S1*S2*...Sn. In this case if S1*S2*...(Sn-1) is smaller than L then the array doesn't need to be as large as L.
I'm afraid your problem understanding is maybe not correct.
You have L. You have a set S of K elements. You must count the sum of quotient of L / Si. For L = 20, K = 1, S = { 5 }, the answer is simply 16 (20 - 20 / 5). But K > 1, so you must consider the common multiples also.
Why loop through a list of subsets? It doesn't involve subset calculation, only division and multiple.
You have K distinct integers. Each number could be a prime number. You must consider common multiples. That's all.
EDIT
L = 20 and S = {3,2,5}
Leaves could be eaten by 3 = 6
Leaves could be eaten by 2 = 10
Leaves could be eaten by 5 = 4
Common multiples of S, less than L, not in S = 6, 10, 15
Actually eaten leaves = 20/3 + 20/2 + 20/5 - 20/6 - 20/10 - 20/15 = 6
You can keep track of the distance until then next touched leaf for each size. The distance to the next touched leaf will be whichever distance happens to be smallest, and you'd subtract this distance from all the others (and wrap whenever the distance is zero).
For example:
int sizes[4] = {2, 5, 7, 9};
int distances[4];
int currentLength = 0;
for(size = 0 to 3) {
distances[size] = sizes[size];
}
while(currentLength < L) {
smallest = INT_MAX;
for(size = 0 to 3) {
if(distances[size] < smallest) smallest = distances[size];
}
for(size = 0 to 3) {
distances[size] -= smallest;
if(distances[size] == 0) distances[size] = sizes[size];
}
while( (smallest > 1) && (currentLength < L) ) {
currentLength++;
printf("%d\n", currentLength;
smallest--;
}
}
#A.06: u r the one with username linkinmew on opc, rite?
Anyways, the answer just requires u to make all possible subsets, and then apply inclusion exclusion principle. This will fall well within the time bounds for the data given. For making all possible subsets, u can easily define a recursive function.
i don't know about programming but in math there is a single theorem which works on a set that has GCD 1
L=20, S=(3,2,5)
(1-1/p)(1-1/q)(1-1/r).....and so on
(1-1/3)(1-1/2)(1-1/5)=(2/3)(1/2)(4/5)=4/15
4/15 means there are 4 numbers in each set of 15 number which are not divisible by any number rest of it can be count manually eg.
16, 17, 18, 19, 20 (only 17 and 19 means there are only 2 numbers thatr can't be divided by any S)
4+2=6
6/20 means there are only 6 numbers in first 20 numbers that can't be divided by any s