diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..34f6f87 --- /dev/null +++ b/.gitignore @@ -0,0 +1,46 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# Jupyter Notebook +.ipynb_checkpoints + +# C++ compiled files +gcd_permutation +verify_solution +test_expected +*.exe +*.o +*.obj + +# IDE files +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS files +.DS_Store +Thumbs.db \ No newline at end of file diff --git a/GCD_PERMUTATION_README.md b/GCD_PERMUTATION_README.md new file mode 100644 index 0000000..10c9d82 --- /dev/null +++ b/GCD_PERMUTATION_README.md @@ -0,0 +1,88 @@ +# GCD Permutation Problem Solution + +## Problem Statement + +Given a permutation `p` of size `n`, find a permutation `q` of size `n` such that `GCD(pi+qi, pi+1+qi+1) >= 3` for all `1 <= i < n`. + +In other words, the greatest common divisor of the sum of any two adjacent positions should be at least 3. + +## Algorithm + +The solution uses multiple construction strategies: + +1. **Reverse Order**: Try `q = [n, n-1, n-2, ..., 1]` +2. **Cyclic Shifts**: Try different cyclic permutations +3. **Brute Force**: For small `n <= 8`, try all permutations +4. **Systematic Search**: Try various shift patterns + +## Implementation + +The main algorithm is in `gcd_permutation.cpp`: + +```cpp +#include +#include +#include +using namespace std; + +int gcd(int a, int b); +bool isValidPermutation(vector& p, vector& q); +void solve(); +``` + +## Usage + +1. Compile the program: +```bash +g++ -o gcd_permutation gcd_permutation.cpp +``` + +2. Run with input: +```bash +./gcd_permutation < test_input.txt +``` + +## Test Cases + +### Input Format +``` +t # Number of test cases +n # Size of permutation +p1 p2 ... pn # The permutation p +``` + +### Example +``` +3 +3 +1 3 2 +5 +5 1 2 4 3 +7 +6 7 1 5 4 3 2 +``` + +### Output +``` +2 3 1 +1 2 4 5 3 +1 7 6 2 3 4 5 +``` + +## Verification + +The solution includes verification tools: + +- `verify_solution.cpp`: Verifies that a given solution satisfies the GCD constraint +- `test_expected.cpp`: Tests specific permutation pairs + +## Complexity + +- **Time**: O(n! * n) in worst case (brute force for small n), O(n) for most practical cases +- **Space**: O(n) for storing permutations + +## Notes + +- The problem guarantees that a solution always exists +- Multiple valid solutions may exist; any valid one is acceptable +- The algorithm prioritizes simple constructions before falling back to brute force \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2d4766c --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +CXX = g++ +CXXFLAGS = -std=c++17 -O2 + +# Main GCD permutation solution +gcd_permutation: gcd_permutation.cpp + $(CXX) $(CXXFLAGS) -o gcd_permutation gcd_permutation.cpp + +# Verification tools +verify_solution: verify_solution.cpp + $(CXX) $(CXXFLAGS) -o verify_solution verify_solution.cpp + +test_expected: test_expected.cpp + $(CXX) $(CXXFLAGS) -o test_expected test_expected.cpp + +# Build all +all: gcd_permutation verify_solution test_expected + +# Test the solution +test: gcd_permutation + ./gcd_permutation < test_input.txt + +# Extended test +test_extended: gcd_permutation + ./gcd_permutation < extended_test_input.txt + +# Verify our solutions +verify: test_expected + ./test_expected + +# Clean compiled files +clean: + rm -f gcd_permutation verify_solution test_expected + +.PHONY: all test test_extended verify clean \ No newline at end of file diff --git a/README.md b/README.md index 43c5926..445aa4f 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,17 @@ It includes data preprocessing, feature engineering, and a comparison between Lo image +## Additional Component: GCD Permutation Problem + +This repository also includes a solution to the GCD Permutation competitive programming problem. See `GCD_PERMUTATION_README.md` for details. + +**Files related to GCD Permutation:** +- `gcd_permutation.cpp` - Main solution +- `verify_solution.cpp` - Solution verification tool +- `test_expected.cpp` - Test validation +- `test_input.txt` - Sample test cases +- `GCD_PERMUTATION_README.md` - Detailed documentation + ## Project Workflow ### 1. Preprocessing diff --git a/extended_test_input.txt b/extended_test_input.txt new file mode 100644 index 0000000..fb9aaa3 --- /dev/null +++ b/extended_test_input.txt @@ -0,0 +1,11 @@ +5 +3 +1 3 2 +5 +5 1 2 4 3 +7 +6 7 1 5 4 3 2 +4 +1 2 3 4 +6 +3 1 4 6 5 2 \ No newline at end of file diff --git a/gcd_permutation.cpp b/gcd_permutation.cpp new file mode 100644 index 0000000..1a3c28f --- /dev/null +++ b/gcd_permutation.cpp @@ -0,0 +1,122 @@ +#include +#include +#include +using namespace std; + +int gcd(int a, int b) { + while (b != 0) { + int temp = b; + b = a % b; + a = temp; + } + return a; +} + +bool isValidPermutation(vector& p, vector& q) { + int n = p.size(); + for (int i = 0; i < n - 1; i++) { + int sum1 = p[i] + q[i]; + int sum2 = p[i + 1] + q[i + 1]; + if (gcd(sum1, sum2) < 3) { + return false; + } + } + return true; +} + +void solve() { + int n; + cin >> n; + vector p(n); + + for (int i = 0; i < n; i++) { + cin >> p[i]; + } + + vector q(n); + + // Strategy: Use a construction that works well in practice + // Based on analysis of the problem, a good construction is often + // to arrange the permutation to create sums that share common factors + + // Construction 1: Try reverse order + for (int i = 0; i < n; i++) { + q[i] = n - i; + } + + if (isValidPermutation(p, q)) { + // Output the permutation q + for (int i = 0; i < n; i++) { + cout << q[i]; + if (i < n - 1) cout << " "; + } + cout << endl; + return; + } + + // Construction 2: Try a pattern that often works + // Use the fact that we want GCD >= 3, so try to make many sums divisible by 3 + for (int i = 0; i < n; i++) { + q[i] = ((n - i - 1 + (n / 2)) % n) + 1; + } + + if (isValidPermutation(p, q)) { + // Output the permutation q + for (int i = 0; i < n; i++) { + cout << q[i]; + if (i < n - 1) cout << " "; + } + cout << endl; + return; + } + + // Construction 3: For small n, use brute force + if (n <= 8) { + for (int i = 0; i < n; i++) { + q[i] = i + 1; + } + + do { + if (isValidPermutation(p, q)) { + // Output the permutation q + for (int i = 0; i < n; i++) { + cout << q[i]; + if (i < n - 1) cout << " "; + } + cout << endl; + return; + } + } while (next_permutation(q.begin(), q.end())); + } + + // Fallback: If nothing works, try a systematic approach + // This should always find a solution as the problem guarantees one exists + for (int shift = 1; shift < n; shift++) { + for (int i = 0; i < n; i++) { + q[i] = (i + shift) % n + 1; + } + if (isValidPermutation(p, q)) { + // Output the permutation q + for (int i = 0; i < n; i++) { + cout << q[i]; + if (i < n - 1) cout << " "; + } + cout << endl; + return; + } + } +} + +int main() { + ios_base::sync_with_stdio(false); + cin.tie(NULL); + + int t; + cin >> t; + + while (t--) { + solve(); + } + + return 0; +} \ No newline at end of file diff --git a/test_expected.cpp b/test_expected.cpp new file mode 100644 index 0000000..992f2c8 --- /dev/null +++ b/test_expected.cpp @@ -0,0 +1,68 @@ +#include +#include +using namespace std; + +int gcd(int a, int b) { + while (b != 0) { + int temp = b; + b = a % b; + a = temp; + } + return a; +} + +bool verify_expected_solution(vector& p, vector& q) { + int n = p.size(); + + cout << "Verification for p = "; + for (int i = 0; i < n; i++) { + cout << p[i] << " "; + } + cout << "and q = "; + for (int i = 0; i < n; i++) { + cout << q[i] << " "; + } + cout << endl; + + for (int i = 0; i < n - 1; i++) { + int sum1 = p[i] + q[i]; + int sum2 = p[i + 1] + q[i + 1]; + int g = gcd(sum1, sum2); + + cout << "GCD(" << sum1 << ", " << sum2 << ") = " << g << endl; + + if (g < 3) { + cout << "FAILED: GCD is " << g << " which is less than 3" << endl; + return false; + } + } + + cout << "PASSED: All GCD values are >= 3" << endl; + return true; +} + +int main() { + // Test our updated solutions + + // Test case 1: p = [1, 3, 2], our q = [2, 3, 1] + vector p1 = {1, 3, 2}; + vector q1 = {2, 3, 1}; + cout << "=== Test Case 1 (Our Solution) ===" << endl; + verify_expected_solution(p1, q1); + cout << endl; + + // Test case 2: p = [5, 1, 2, 4, 3], our q = [1, 2, 4, 5, 3] + vector p2 = {5, 1, 2, 4, 3}; + vector q2 = {1, 2, 4, 5, 3}; + cout << "=== Test Case 2 (Our Solution) ===" << endl; + verify_expected_solution(p2, q2); + cout << endl; + + // Test case 3: p = [6, 7, 1, 5, 4, 3, 2], our q = [1, 7, 6, 2, 3, 4, 5] + vector p3 = {6, 7, 1, 5, 4, 3, 2}; + vector q3 = {1, 7, 6, 2, 3, 4, 5}; + cout << "=== Test Case 3 (Our Solution) ===" << endl; + verify_expected_solution(p3, q3); + + return 0; +} \ No newline at end of file diff --git a/test_input.txt b/test_input.txt new file mode 100644 index 0000000..d9422f4 --- /dev/null +++ b/test_input.txt @@ -0,0 +1,7 @@ +3 +3 +1 3 2 +5 +5 1 2 4 3 +7 +6 7 1 5 4 3 2 \ No newline at end of file diff --git a/verify_solution.cpp b/verify_solution.cpp new file mode 100644 index 0000000..07e7ed6 --- /dev/null +++ b/verify_solution.cpp @@ -0,0 +1,66 @@ +#include +#include +using namespace std; + +int gcd(int a, int b) { + while (b != 0) { + int temp = b; + b = a % b; + a = temp; + } + return a; +} + +bool verify_solution(vector& p, vector& q) { + int n = p.size(); + + cout << "Verification for p = "; + for (int i = 0; i < n; i++) { + cout << p[i] << " "; + } + cout << "and q = "; + for (int i = 0; i < n; i++) { + cout << q[i] << " "; + } + cout << endl; + + for (int i = 0; i < n - 1; i++) { + int sum1 = p[i] + q[i]; + int sum2 = p[i + 1] + q[i + 1]; + int g = gcd(sum1, sum2); + + cout << "GCD(" << sum1 << ", " << sum2 << ") = " << g << endl; + + if (g < 3) { + cout << "FAILED: GCD is " << g << " which is less than 3" << endl; + return false; + } + } + + cout << "PASSED: All GCD values are >= 3" << endl; + return true; +} + +int main() { + // Test case 1: p = [1, 3, 2], q = [3, 2, 1] + vector p1 = {1, 3, 2}; + vector q1 = {3, 2, 1}; + cout << "=== Test Case 1 ===" << endl; + verify_solution(p1, q1); + cout << endl; + + // Test case 2: p = [5, 1, 2, 4, 3], q = [5, 4, 3, 2, 1] + vector p2 = {5, 1, 2, 4, 3}; + vector q2 = {5, 4, 3, 2, 1}; + cout << "=== Test Case 2 ===" << endl; + verify_solution(p2, q2); + cout << endl; + + // Test case 3: p = [6, 7, 1, 5, 4, 3, 2], q = [7, 6, 5, 4, 3, 2, 1] + vector p3 = {6, 7, 1, 5, 4, 3, 2}; + vector q3 = {7, 6, 5, 4, 3, 2, 1}; + cout << "=== Test Case 3 ===" << endl; + verify_solution(p3, q3); + + return 0; +} \ No newline at end of file