1. 程式人生 > >ZOJ-4061 Magic Multiplication 2018年青島區域賽現場賽D題(思維 + 暴力構造)

ZOJ-4061 Magic Multiplication 2018年青島區域賽現場賽D題(思維 + 暴力構造)

題目連結:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4061

題目大意:題目定義一個運算子\otimes對於數A和數B的運演算法則為

A\otimes B=\sum_{i = 1}^{n}\sum_{j=1}^{m}a_{i}*b_{j}a_{i} 表示數A的第 i 位數,b_{j}表示數B的第 j 位數,現在令字串C=A\otimes B,這裡的加法為字串連線的相加。

比如23\otimes 45=8101215,最後的結果由各位運算的結果連線起來得到。

現在給出最終的結果串C,以及A的長度n和B的長度m,要你求出原來的A序列和B序列。

題目思路:由於最終串是由n*m組一位數相乘得到的結果連線而成的,我們可以很容易知道一位數和一位數相乘最多得到一個兩位數,而且對於一個一位數a,如果另一個一位數 b 滿足 b % a == 0,那麼就一定不存在一個一位數 x 使得(b*10 + x) % a == 0。

所以 在將最終結果串拆開來的時候,對於乘積為c_{ij}時,a_{i} 只會有唯一的 b_{j} 與之對應。

因此我們就可以考慮對a_{1}的值進行列舉,先將結果串分解,將滿足當前a_{1}值的B陣列的值求出來。接著再用求出來的B陣列將a_{2}-a_{n}的值求出來,再對正確性進行驗證即可。

由於a_1的取值只有可能是1~9,所以這個解法的時間複雜度為O(9*\sum len(C))

具體實現看程式碼:

#include <bits/stdc++.h>
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define MP make_pair
#define lowbit(x) x&-x
#define clr(a) memset(a,0,sizeof(a))
#define _INF(a) memset(a,0x3f,sizeof(a))
#define FIN freopen("in.txt","r",stdin)
#define FOUT freopen("out.txt","w",stdout)
#define IOS ios::sync_with_stdio(false)
#define fuck(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int MX = 2e5 + 50;

int n, m, _;
char s[MX];
int a[MX], b[MX], c[MX];

int main() {
    // FIN;
    for (scanf("%d", &_); _; _--) {
        scanf("%d%d", &n, &m);
        scanf("%s", s + 1);
        int len = strlen(s + 1);
        if (2ll * n * m < len || len < 1ll * n * m) {
            puts("Impossible");
            continue;
        }
        bool ok = 1;
        for (int i = 1; i <= len; i++) c[i] = s[i] - '0';
        for (int i = 1; i <= 9; i++) {
            int now = 0, flag = 1, cnt = 0, pos = len + 1;
            for (int j = 1; j <= n; j++) a[j] = -1;
            for (int j = 1; j <= m; j++) b[j] = -1;
            for (int j = 1; j <= len; j++) {
                if (cnt == m) {
                    pos = j;
                    break;
                }
                now = c[j];
                if (now % i == 0) b[++cnt] = now / i;
                else {
                    if (j == len) {
                        flag = 0;
                        break;
                    }
                    now = now * 10 + c[j + 1]; j++;
                    if (now % i != 0 || now / i >= 10) {
                        flag = 0;
                        break;
                    }
                    b[++cnt] = now / i;
                }
            }
            for (int j = 1; j <= m; j++) if (b[j] == -1) flag = 0;
            if (flag) {
                ok = 1;
                if (n == 1) {
                    a[1] = i;
                    if (pos <= len) ok = 0;
                } else {
                    a[1] = i;
                    int tmp = 2;
                    cnt = 1;
                    for (int j = pos; j <= len; j++) {
                        if (cnt == m + 1) cnt = 1, tmp++;
                        now = c[j];
                        if (b[cnt] == 0) {
                            if (now != 0) {
                                ok = 0;
                                break;
                            }
                            cnt++;
                            continue;
                        }
                        if (now % b[cnt] != 0) {
                            if (j == len) {
                                ok = 0;
                                break;
                            }
                            now = now * 10 + c[j + 1]; j++;
                            if (now % b[cnt] != 0 || now / b[cnt] >= 10) {
                                ok = 0;
                                break;
                            }
                            if (a[tmp] != -1) {
                                if (a[tmp] != now / b[cnt]) {
                                    ok = 0;
                                    break;
                                }
                            }
                            a[tmp] = now / b[cnt];
                        } else {
                            if (a[tmp] != -1) {
                                if (a[tmp] != now / b[cnt]) {
                                    ok = 0;
                                    break;
                                }
                            }
                            a[tmp] = now / b[cnt];
                        }
                        cnt++;
                    }
                    if (tmp != n || cnt != m + 1) ok = 0;
                }
                if (ok) {
                    for (int j = 1; j <= n; j++) printf("%d", a[j]);
                    printf(" ");
                    for (int j = 1; j <= m; j++) printf("%d", b[j]);
                    printf("\n");
                    break;
                }
            }
        }
        if (!ok) puts("Impossible");
    }
    return 0;
}