Skip to content

Commit

Permalink
Merge pull request #245 from pdp-archive/36-bitsign
Browse files Browse the repository at this point in the history
36 bitsign
  • Loading branch information
Dim131 authored May 6, 2024
2 parents 3c31261 + 504605c commit 446ff82
Show file tree
Hide file tree
Showing 10 changed files with 436 additions and 0 deletions.
13 changes: 13 additions & 0 deletions _data/contests/36-PDP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,16 @@ luckyagain:
solution_tags: ["map", "bst", "counting", "decimal numbers", "number bases"]
on_judge: false
points: 30

bitsign:
full_name: "Bits με υπογραφή"
stage: "c"
statement_pdf_url: "https://drive.google.com/file/d/1AXuG5L4SzRkTnljViElY8qWqOvNoHOTd/view"
statement_md: true
testcases_url: ""
solution: true
solution_author: ""
codes_in_git: true
solution_tags: ["dp", "exhaustive search", "precomputation"]
on_judge: false
points: 30
35 changes: 35 additions & 0 deletions _includes/source_code/code/36-PDP/bitsign/TASK
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
TASK(
name = "bitsign",
test_count = 21,
files_dir = "testdata/36-PDP/bitsign/",
input_file = "bitsign.in",
output_file = "bitsign.out",
time_limit = 1,
mem_limit = 256,
solutions = [
SOLUTION(
name = "bitsign_dp_n2",
source = "bitsign_dp_n2.cc",
passes_all,
lang = "c++",
),
SOLUTION(
name = "bitsign_dp_n2_mem",
source = "bitsign_dp_n2_mem.cc",
passes_all,
lang = "c++",
),
SOLUTION(
name = "bitsign_dp_n3",
source = "bitsign_dp_n3.cc",
passes_all,
lang = "c++",
),
SOLUTION(
name = "bitsign_brute_force",
source = "bitsign_brute_force.cc",
passes_up_to = 8,
lang = "c++",
),
]
)
58 changes: 58 additions & 0 deletions _includes/source_code/code/36-PDP/bitsign/bitsign_brute_force.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include <cstdio>
#include <vector>

const long MOD = 1'000'000'007L;
const int MAXN = 2'000;

char c[MAXN + 2];
std::vector<int> s;

long total;
int N, M;

/* Δοκιμάζουμε τις δυνατές τιμές για το c[c_idx], δεδομένου ότι έχουμε συμπληρώσει
τις τιμές για τα c[0..c_idx-1], ότι έχουμε φτιάξει τα διαστήματα s[0..s_idx-1] και
ότι το μήκος της τωρινής ακολουθίας από άσους είναι len_of_ones. */
void solve(int c_idx, int len_of_ones, int s_idx) {
if (c_idx == N + 1) {
// Συμπληρώσαμε όλη την ακολουθία. Ελέγχουμε ότι δεν μας περίσσεψε κάτι.
if (s_idx == s.size() && len_of_ones == 0) total = (total + 1) % MOD;
return;
}
// Δοκιμάζουμε να βάλουμε έναν άσο. Επεκτείνεται η τωρινή ακολουθία κατά ένα.
if (c[c_idx] == '1' || c[c_idx] == '.') solve(c_idx + 1, len_of_ones + 1, s_idx);
// Δοκιμάζουμε να βάλουμε ένα μηδενικό. Αν υπάρχει τωρινή ακολουθία από άσσους
// με μήκος s[s_idx], την ολοκληρώνουμε.
if (c[c_idx] == '0' || c[c_idx] == '.') {
if (s_idx < s.size() && len_of_ones == s[s_idx]) solve(c_idx + 1, 0, s_idx + 1);
else if (len_of_ones == 0) solve(c_idx + 1, 0, s_idx);
}
}

int main() {
FILE *fi = fopen("bitsign.in", "r");
FILE *fo = fopen("bitsign.out", "w");

int T;
fscanf(fi, "%d\n", &T);
while (T--) {
fscanf(fi, "%d %d\n", &N, &M);
for (int i = 0; i < N; ++i) {
fscanf(fi, "%c", &c[i]);
}
c[N] = '0';
s.resize(M);
for (int i = 0; i < M; ++i) {
fscanf(fi, "%d", &s[i]);
}

total = 0;
solve(0, 0, 0);

fprintf(fo, "%ld\n", total);
}

fclose(fi);
fclose(fo);
return 0;
}
57 changes: 57 additions & 0 deletions _includes/source_code/code/36-PDP/bitsign/bitsign_dp_n2.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include <cstdio>
#include <vector>

const long MOD = 1'000'000'007L;
const int MAXN = 2'000;

char c[MAXN + 2];

int main() {
FILE *fi = fopen("bitsign.in", "r");
FILE *fo = fopen("bitsign.out", "w");

int T;
fscanf(fi, "%d\n", &T);
while (T--) {
int N, M;

fscanf(fi, "%d %d\n", &N, &M);
for (int i = 0; i < N; ++i) {
fscanf(fi, "%c", &c[i+1]);
}
c[0] = c[N+1] = '0';
std::vector<int> s(M);
for (int i = 0; i < M; ++i) {
fscanf(fi, "%d", &s[i]);
}

// Προϋπολογίζουμε το πρώτο μηδενικό στα δεξιά του κάθε στοιχείου.
std::vector<int> first_zero_to_left(N + 2);
for (int i = N + 1; i >= 0; --i) {
if (c[i] == '0') {
first_zero_to_left[i] = i;
continue;
}
first_zero_to_left[i] = std::min(first_zero_to_left[i+1], i);
while (c[first_zero_to_left[i]] != '0') --first_zero_to_left[i];
}

// Ο υπολογισμός με δυναμικό προγραμματισμό.
std::vector<std::vector<int>> dp(M+1, std::vector<int>(N+2, 0));
for (int i = 0; i <= N+1 && c[i] != '1'; ++i) dp[0][i] = 1;

for (int j = 1; j <= M; ++j) {
for (int i = 1; i <= N + 1; ++i) {
if (c[i] == '1') continue;
dp[j][i] = dp[j][i-1]; // Μπορούμε απλά να προσθέσουμε ένα 0.
if (i - first_zero_to_left[i - 1] - 1 >= s[j-1]) // Υπάρχουν αρκετά ‘1' ή ‘.'?
dp[j][i] = (dp[j][i] + dp[j - 1][i - s[j-1] - 1]) % MOD;
}
}
fprintf(fo, "%ld\n", dp[M][N+1]);
}

fclose(fi);
fclose(fo);
return 0;
}
65 changes: 65 additions & 0 deletions _includes/source_code/code/36-PDP/bitsign/bitsign_dp_n2_mem.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include <cstdio>
#include <vector>

const long MOD = 1'000'000'007L;
const int MAXN = 2'000;

char c[MAXN + 2];

inline int C(int i) { return i & 1; }

int main() {
FILE *fi = fopen("bitsign.in", "r");
FILE *fo = fopen("bitsign.out", "w");

int T;
fscanf(fi, "%d\n", &T);
while (T--) {
int N, M;

fscanf(fi, "%d %d\n", &N, &M);
for (int i = 0; i < N; ++i) {
fscanf(fi, "%c", &c[i+1]);
}
c[0] = c[N+1] = '0';
std::vector<int> s(M);
for (int i = 0; i < M; ++i) {
fscanf(fi, "%d", &s[i]);
}

// Προϋπολογίζουμε το πρώτο μηδενικό στα δεξιά του κάθε στοιχείου.
std::vector<int> first_zero_to_left(N + 2);
for (int i = N + 1; i >= 0; --i) {
if (c[i] == '0') {
first_zero_to_left[i] = i;
continue;
}
first_zero_to_left[i] = std::min(first_zero_to_left[i+1], i);
while (c[first_zero_to_left[i]] != '0') --first_zero_to_left[i];
}

// Ο υπολογισμός με δυναμικό προγραμματισμό.
std::vector<int> dp[2];
dp[0].resize(N+2, 0);
dp[1].resize(N+2, 0);
for (int i = 0; i <= N+1 && c[i] != '1'; ++i) dp[0][i] = 1;

for (int j = 1; j <= M; ++j) {
dp[C(j)][0] = 0;
for (int i = 1; i <= N + 1; ++i) {
if (c[i] == '1') {
dp[C(j)][i] = 0;
} else {
dp[C(j)][i] = dp[C(j)][i-1]; // Μπορούμε απλά να προσθέσουμε ένα 0.
if (i - first_zero_to_left[i - 1] - 1 >= s[j-1]) // Υπάρχουν αρκετά ‘1' ή ‘.'?
dp[C(j)][i] = (dp[C(j)][i] + dp[C(j - 1)][i - s[j-1] - 1]) % MOD;
}
}
}
fprintf(fo, "%ld\n", dp[C(M)][N+1]);
}

fclose(fi);
fclose(fo);
return 0;
}
49 changes: 49 additions & 0 deletions _includes/source_code/code/36-PDP/bitsign/bitsign_dp_n3.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include <cstdio>
#include <vector>

const long MOD = 1'000'000'007L;
const int MAXN = 2'000;

char c[MAXN + 2];

int main() {
FILE *fi = fopen("bitsign.in", "r");
FILE *fo = fopen("bitsign.out", "w");

int T;
fscanf(fi, "%d\n", &T);
while (T--) {
int N, M;

fscanf(fi, "%d %d\n", &N, &M);
for (int i = 0; i < N; ++i) {
fscanf(fi, "%c", &c[i+1]);
}
c[0] = c[N+1] = '0';
std::vector<int> s(M);
for (int i = 0; i < M; ++i) {
fscanf(fi, "%d", &s[i]);
}

// Ο υπολογισμός με δυναμικό προγραμματισμό.
std::vector<std::vector<int>> dp(M+1, std::vector<int>(N+2, 0));
for (int i = 0; i <= N+1 && c[i] != '1'; ++i) dp[0][i] = 1;

for (int j = 1; j <= M; ++j) {
for (int i = 1; i <= N + 1; ++i) {
if (c[i] == '1') continue;
dp[j][i] = dp[j][i-1]; // Μπορούμε απλά να προσθέσουμε ένα 0.
int first_zero_to_left = i - 1;
while (c[first_zero_to_left] != '0') --first_zero_to_left;
if (i - first_zero_to_left - 1 >= s[j-1]) { // Υπάρχουν αρκετά ‘1' ή ‘.'?
dp[j][i] = (dp[j][i] + dp[j - 1][i - s[j-1] - 1]) % MOD;
}
}
}
fprintf(fo, "%ld\n", dp[M][N+1]);
}

fclose(fi);
fclose(fo);
return 0;
}
Loading

0 comments on commit 446ff82

Please sign in to comment.