Codeforces Round #451 (Div. 2) F. Restoring the Expression(哈希)

F. Restoring the Expression

Problem Statement

    A correct expression of the form a+b=c was written; a, b and c are non-negative integers without leading zeros. In this expression, the plus and equally signs were lost. The task is to restore the expression. In other words, one character ‘+’ and one character ‘=’ should be inserted into given sequence of digits so that:

    character’+’ is placed on the left of character ‘=’,
    characters ‘+’ and ‘=’ split the sequence into three non-empty subsequences consisting of digits (let’s call the left part a, the middle part — b and the right part — c),
    all the three parts a, b and c do not contain leading zeros,
    it is true that a+b=c.

    It is guaranteed that in given tests answer always exists.

Input

    The first line contains a non-empty string consisting of digits. The length of the string does not exceed 106 .

Output

    Output the restored expression. If there are several solutions, you can print any of them.
    Note that the answer at first should contain two terms (divided with symbol ‘+’), and then the result of their addition, before which symbol’=’ should be.
    Do not separate numbers and operation signs with spaces. Strictly follow the output format given in the examples.
    If you remove symbol ‘+’ and symbol ‘=’ from answer string you should get a string, same as string from the input data.

Examples

Example 1
    Input
        12345168
    Output
        123+45=168
Example 2
    Input
        099
    Output
        0+9=9
Example 3
    Input
        123123123456456456579579579
    Output
        123123123+456456456=579579579

题意

    给定一个全由数字组成的字符串,让你在中间添加一个加号和一个等号,使它所表示出来的等式成立。且前两个数必为加数,即输出格式为a+b=c。

思路

    其实,这题不难。对于一个两个数加法的式子,我们知道,结果最多也只会比最大的那个数多1位,要不结果就和两个加数中大的那个数的位数相等,只有两种情况,于是我们可以这样考虑,对于给出的字符串,我们先进行哈希(我模数取了1e9+7,可以过),然后从右往左枚举结果有几位,那么左边的加数有两种情况,一种是第一个加数与结果位数相等或少1,另一种是第二个加数与结果位数相等或少1,那对于每一位,我们最多只有4种情况,且有很多情况都是无用的。
    那么对于一个数如何哈希回来,我们可以对那个字符串进行后缀和,然后对于一个区间[l,r]为一个选定的数,我们就可以通过sum[l]-sum[r+1]来获得这个数哈希以后乘上 10lenr 的值,然后我们要除掉 10lenr ,这个可以通过预处理逆元来完成,最后判一下可不可行,可行直接输出就好了。

Code

#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
bool Finish_read;
template<class T>inline void read(T &x){Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
/*================Header Template==============*/
const ll mod=1e9+7;
int n;
char s[1000010];
ll num[1000010],inv[1000010];
inline ll pw(ll a,ll b) {
    ll res=1;
    while(b) {
        if(b&1)
            res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
inline void printstr(int l,int r) {
    for(int i=l;i<=r;i++)
        putchar(s[i]);
}
inline ll calc(int l,int r) {
    ll val=((num[l]-num[r+1])%mod+mod)%mod;
//  cout<<"interval :"<<l<<"->"<<r<<" get:"<<val<<endl;
    return (val*inv[n-r]%mod);
}
inline bool check(ll l1,ll l2,ll l3) {
//  cout<<"Now check three lengths:"<<l1<<" and "<<l2<<" and "<<l3<<endl;
    if(l1>l3||l2>l3||l1<1||l2<1||l3<1)
        return 0;
    int pl1=1,pl2=l1+1,pl3=l1+l2+1,pr1=l1,pr2=l1+l2,pr3=l1+l2+l3;
//  cout<<"Num one:"<<pl1<<" to "<<pr1<<" Num two:"<<pl2<<" to "<<pr2<<" Num three:"<<pl3<<" to "<<pr3<<endl;
    if(s[pl1]=='0'&&pr1-pl1+1!=1)
        return 0;
    if(s[pl2]=='0'&&pr2-pl2+1!=1)
        return 0;
    if(s[pl3]=='0'&&pr3-pl3+1!=1)
        return 0;
//  cout<<"First num:"<<calc(pl1,pr1)<<" Second num:"<<calc(pl2,pr2)<<" Third num:"<<calc(pl3,pr3)<<endl;
    if((calc(pl1,pr1)+calc(pl2,pr2))%mod==calc(pl3,pr3)) {
//      cout<<pl1<<" "<<pr1<<" "<<pl2<<" "<<pr2<<" "<<pl3<<" "<<pr3<<endl;
        printstr(pl1,pr1);
        putchar('+');
        printstr(pl2,pr2);
        putchar('=');
        printstr(pl3,pr3);
        return 1;
    }
    return 0;
}
int main() {
//  freopen("F.in","r",stdin);
    inv[1000000]=pw(10LL,1000000LL);
    inv[1000000]=pw(inv[1000000],mod-2);
    for(int i=999999;~i;i--)
        inv[i]=inv[i+1]*10%mod;
    scanf("%s",s+1);
//  for(int i=0;i<=10;i++)
//      cout<<inv[i]<<endl;
    n=strlen(s+1);
//  cout<<n<<endl;
//  for(int i=1;i<=n;i++)
//      putchar(s[i]);
    num[n+1]=0;
    for(int i=n;i;i--)
        num[i]=(num[i+1]+(s[i]-'0')*pw(10LL,n-i)%mod)%mod;
//  for(int i=n;i;i--)
//      cout<<num[i]<<" ";
//  cout<<endl;
    for(int div=1;div<=n;div++)
        if(check(div-1,n-div-(div-1),div)||check(div,n-div-div,div)||check(n-div-(div-1),div-1,div)||check(n-div-div,div,div))
            return 0;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值