ZOJ-4061 Magic Multiplication 2018年青岛区域赛现场赛D题(思维 + 暴力构造)

7 篇文章 0 订阅

题目链接: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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值