ZOJ - 4061 Magic Multiplication (直接模拟)

青岛……
没想到我大三了还会打铁
果然是太菜了


题意是两个数A,B上每一位相乘,然后顺次接在一起,现在给你结果C和原来两个数字的长度,要求恢复成原来的数字A,B。

两个个位数想乘,结果一定是小于等于两位的。我们首先能想到枚举A的第一个数字,然后用C恢复B,然后用B恢复A,中途判断能不能构成C就行。相当于每次搜都走一次C的长度,时间复杂度基本上是 O ( 9 l e n c ) O(9len_c) O(9lenc)的,从数据上看不会超时。
如果暴力搜的话,会发现其实有很多取一位还是取两位的问题,我们要是能把这个地方优化掉,就不用回溯了。
我们列出99乘法表……会发现这样的规律:
两位数的乘积,第一位一定是小于这两个数的
这样就好办了,我们利用这个就能一次性判断这个位数了

#include <bits/stdc++.h>
#include <cstring>
#define ll long long
#define endl '\n'
using namespace std;
const int MAXN = 2e5 + 10;
char s[MAXN];
int a[MAXN],b[MAXN],c[MAXN];
int main()
{
    // freopen("input.txt","w",stdout);
    //  data_gene(10000);
    //freopen("input.txt","r",stdin);
    int ca;
    scanf("%d",&ca);
    while(ca--)
    {
        int n,m;
        scanf("%d %d",&n,&m);
        scanf("%s",s);
        int clen = strlen(s);
        for(int i = 0; i<clen; ++i)
            c[i] = s[i]-'0';
        bool ok = 0;
        for(int a1 = 1; a1 <= 9; ++a1)
        {
            int f = 1,p = 0;
            for(int i = 1; i<=m; ++i)
            {
                int t1 = c[p];
                if(t1 == 0)
                {
                    p++;
                    b[i] = 0;
                }
                else if(t1 < a1)
                {
                    t1 = t1 * 10 + c[p+1];
                    if(t1 % a1 != 0)
                    {
                        f = 0;
                        break;
                    }
                    b[i] = t1/a1;
                    p+=2;
                }
                else
                {
                    if(t1 % a1 != 0)
                    {
                        f = 0;
                        break;
                    }
                    b[i] = t1/a1;
                    p++;
                }
            }
            if(!f)
                continue;
            a[1] = a1;
            for(int i = 2; i<=n; ++i)
            {
                int t1 = c[p];
                int ta;
                if(t1 == 0)
                {
                    ta = 0;
                    p++;
                }
                else if(t1 < b[1])
                {
                    t1 = t1*10 + c[p+1];
                    if(t1 % b[1] != 0)
                    {
                        f = 0;break;
                    }
                    p+=2;
                    ta = t1/b[1];
                }
                else
                {
                    p++;
                    if(t1 % b[1] != 0)
                    {
                        f = 0;break;
                    }
                    ta = t1/b[1];
                }
                bool ff = 1;
                for(int j = 2; j<=m; ++j)
                {
                    int t2 = ta*b[j];
                    if(t2 == c[p])
                    {
                        p++;
                    }
                    else if(t2 == c[p]*10 + c[p+1])
                        p+=2;
                    else
                    {
                        ff = 0;
                        break;
                    }
                }
                if(ff)
                    a[i] = ta;
                else
                {
                    f = 0;
                    break;
                }
            }
            if(!f)
                continue;
            if(p != clen)
                continue;
            ok = 1;
            for(int i =1; i<=n; i++)
                printf("%d",a[i]);
            printf(" ");
            for(int i = 1; i<=m; i++)
                printf("%d",b[i]);
            printf("\n");
            break;
        }
        if(!ok)
            puts("Impossible");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值