ZOJ 4061 Magic Multiplication——暴搜
阿新 • • 發佈:2018-11-16
題意:規則舉例:1234*5678=5678101214161516212420242832,現在給出最終串,以及兩個原串的長度,問兩個原串是多少,設原串為A B,多解先令A儘量小,然後再令B儘量小
所有傳的長度都在2e5以內,除非串只有一個0,否則沒有前導0
思路:現場賽的時候拿到這個題一開始沒什麼思路放掉了,最後也沒時間想了,賽後想一想其實暴搜就可以,因為匹配的概率本來就比較低,所以遞迴總次數也不會很多,當然需要一些技巧優化一下
首先可以明確的是確定了A的第一位,B也就確定了,以此為出發點進行暴搜,每次搜尋列舉A的當前位,然後乘上B與C進行匹配,匹配成功繼續遞迴,這樣效率就挺高了,在此之上我發現兩個串相乘(按題目中的定義)後的長度最小為len1*len2,最大為2*len1*len2,根據這一點可以在最小長度大於C的剩餘長度或者最大長度小於C的剩餘長度時剪枝,快10ms而已。。。弱剪枝
注意各種細節,判一下0什麼的就做完了
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5 + 10; int T, N, M, L; int cnt, pos; char A[maxn], B[maxn], C[maxn]; bool getB(int x) { cnt = 0; pos = 0; for (int i = 0; i < L; i++) { int t = C[i] - '0'; if (x <= t || t == 0) { if (t % x) return false; else B[cnt++] = t / x + '0'; } else { if (i == L - 1) return false; else { i++; t = t * 10 + C[i]-'0'; if (t % x) return false; else B[cnt++] = t / x + '0'; } } if (cnt == M) { B[M] = 0; pos = i; return true; } } return false; } bool dfs(int a, int c) { if (a == N && c == L) return true; if (a == N || c >= L) return false; // if (1LL*(N-a)*M > L-c || 2LL*(N-a)*M < L-c) return false; for (int i = 0; i <= 9; i++) { A[a] = i + '0'; int p = c; bool ok = true; for (int j = 0; j < M; j++) { if (i * (B[j]-'0') < 10) { if (i * (B[j]-'0') != C[p]-'0') { ok = false; break; } else p++; } else { int d1 = i*(B[j]-'0')/10; int d2 = i*(B[j]-'0')%10; if (d1 == C[p]-'0' && p != L-1 && d2 == C[p+1]-'0') p += 2; else { ok = false; break; } } } if (ok) { if (dfs(a+1, p)) return true; } } return false; } void solve() { for (int i = 1; i <= 9; i++) { if (getB(i)) { A[0] = i + '0'; if (dfs(1, pos+1)) { for (int j = 0; j < N; j++) printf("%c", A[j]); printf(" "); for (int j = 0; j < M; j++) printf("%c", B[j]); printf("\n"); return; } } } printf("Impossible\n"); } int main() { scanf("%d", &T); while (T--) { scanf("%d%d", &N, &M); getchar(); scanf("%s", C); L = strlen(C); if (L == 1 && C[0] == '0') { if (N == 1 && M != 1) { printf("0 1"); for (int i = 1; i < M; i++) printf("0"); printf("\n"); } else if (N != 1 && M == 1) { printf("1"); for (int i = 1; i < N; i++) printf("0"); printf(" 0\n"); } else if (N == 1 && M == 1) { printf("0 0\n"); } else { printf("Impossible\n"); } } else if (1LL*N*M > L || 2LL*N*M < L) { printf("Impossible\n"); } else { solve(); } } return 0; }